updated core to 8.6.1 via composer
This commit is contained in:
@@ -335,11 +335,11 @@ class DbUpdateController extends ControllerBase {
|
||||
|
||||
// Warn the user if any updates were incompatible.
|
||||
if ($incompatible_updates_exist) {
|
||||
drupal_set_message($this->t('Some of the pending updates cannot be applied because their dependencies were not met.'), 'warning');
|
||||
$this->messenger()->addWarning($this->t('Some of the pending updates cannot be applied because their dependencies were not met.'));
|
||||
}
|
||||
|
||||
if (empty($count)) {
|
||||
drupal_set_message($this->t('No pending updates.'));
|
||||
$this->messenger()->addStatus($this->t('No pending updates.'));
|
||||
unset($build);
|
||||
$build['links'] = [
|
||||
'#theme' => 'links',
|
||||
@@ -524,7 +524,7 @@ class DbUpdateController extends ControllerBase {
|
||||
$build['status_report'] = [
|
||||
'#type' => 'status_report',
|
||||
'#requirements' => $requirements,
|
||||
'#suffix' => $this->t('Check the messages and <a href=":url">try again</a>.', [':url' => $try_again_url])
|
||||
'#suffix' => $this->t('Check the messages and <a href=":url">try again</a>.', [':url' => $try_again_url]),
|
||||
];
|
||||
|
||||
$build['#title'] = $this->t('Requirements problem');
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace Drupal\system\Controller;
|
||||
|
||||
use Drupal\Component\Utility\Crypt;
|
||||
use Drupal\Component\Utility\Tags;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Entity\EntityAutocompleteMatcher;
|
||||
use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
|
||||
@@ -81,7 +80,7 @@ class EntityAutocompleteController extends ControllerBase {
|
||||
// Get the typed string from the URL, if it exists.
|
||||
if ($input = $request->query->get('q')) {
|
||||
$typed_string = Tags::explode($input);
|
||||
$typed_string = Unicode::strtolower(array_pop($typed_string));
|
||||
$typed_string = mb_strtolower(array_pop($typed_string));
|
||||
|
||||
// Selection settings are passed in as a hashed key of a serialized array
|
||||
// stored in the key/value store.
|
||||
|
||||
@@ -100,7 +100,7 @@ class SystemController extends ControllerBase {
|
||||
public function overview($link_id) {
|
||||
// Check for status report errors.
|
||||
if ($this->systemManager->checkRequirements() && $this->currentUser()->hasPermission('administer site configuration')) {
|
||||
drupal_set_message($this->t('One or more problems were detected with your Drupal installation. Check the <a href=":status">status report</a> for more information.', [':status' => $this->url('system.status')]), 'error');
|
||||
$this->messenger()->addError($this->t('One or more problems were detected with your Drupal installation. Check the <a href=":status">status report</a> for more information.', [':status' => $this->url('system.status')]));
|
||||
}
|
||||
// Load all menu links below it.
|
||||
$parameters = new MenuTreeParameters();
|
||||
@@ -187,7 +187,7 @@ class SystemController extends ControllerBase {
|
||||
uasort($themes, 'system_sort_modules_by_info_name');
|
||||
|
||||
$theme_default = $config->get('default');
|
||||
$theme_groups = ['installed' => [], 'uninstalled' => []];
|
||||
$theme_groups = ['installed' => [], 'uninstalled' => []];
|
||||
$admin_theme = $config->get('admin');
|
||||
$admin_theme_options = [];
|
||||
|
||||
|
||||
@@ -71,15 +71,15 @@ class ThemeController extends ControllerBase {
|
||||
if (!empty($themes[$theme])) {
|
||||
// Do not uninstall the default or admin theme.
|
||||
if ($theme === $config->get('default') || $theme === $config->get('admin')) {
|
||||
drupal_set_message($this->t('%theme is the default theme and cannot be uninstalled.', ['%theme' => $themes[$theme]->info['name']]), 'error');
|
||||
$this->messenger()->addError($this->t('%theme is the default theme and cannot be uninstalled.', ['%theme' => $themes[$theme]->info['name']]));
|
||||
}
|
||||
else {
|
||||
$this->themeHandler->uninstall([$theme]);
|
||||
drupal_set_message($this->t('The %theme theme has been uninstalled.', ['%theme' => $themes[$theme]->info['name']]));
|
||||
$this->messenger()->addStatus($this->t('The %theme theme has been uninstalled.', ['%theme' => $themes[$theme]->info['name']]));
|
||||
}
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('The %theme theme was not found.', ['%theme' => $theme]), 'error');
|
||||
$this->messenger()->addError($this->t('The %theme theme was not found.', ['%theme' => $theme]));
|
||||
}
|
||||
|
||||
return $this->redirect('system.themes_page');
|
||||
@@ -108,15 +108,15 @@ class ThemeController extends ControllerBase {
|
||||
try {
|
||||
if ($this->themeHandler->install([$theme])) {
|
||||
$themes = $this->themeHandler->listInfo();
|
||||
drupal_set_message($this->t('The %theme theme has been installed.', ['%theme' => $themes[$theme]->info['name']]));
|
||||
$this->messenger()->addStatus($this->t('The %theme theme has been installed.', ['%theme' => $themes[$theme]->info['name']]));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('The %theme theme was not found.', ['%theme' => $theme]), 'error');
|
||||
$this->messenger()->addError($this->t('The %theme theme was not found.', ['%theme' => $theme]));
|
||||
}
|
||||
}
|
||||
catch (PreExistingConfigException $e) {
|
||||
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
|
||||
drupal_set_message(
|
||||
$this->messenger()->addError(
|
||||
$this->formatPlural(
|
||||
count($config_objects),
|
||||
'Unable to install @extension, %config_names already exists in active configuration.',
|
||||
@@ -124,12 +124,11 @@ class ThemeController extends ControllerBase {
|
||||
[
|
||||
'%config_names' => implode(', ', $config_objects),
|
||||
'@extension' => $theme,
|
||||
]),
|
||||
'error'
|
||||
])
|
||||
);
|
||||
}
|
||||
catch (UnmetDependenciesException $e) {
|
||||
drupal_set_message($e->getTranslatedMessage($this->getStringTranslation(), $theme), 'error');
|
||||
$this->messenger()->addError($e->getTranslatedMessage($this->getStringTranslation(), $theme));
|
||||
}
|
||||
|
||||
return $this->redirect('system.themes_page');
|
||||
@@ -171,17 +170,18 @@ class ThemeController extends ControllerBase {
|
||||
// theme.
|
||||
$admin_theme = $config->get('admin');
|
||||
if ($admin_theme != 0 && $admin_theme != $theme) {
|
||||
drupal_set_message($this->t('Please note that the administration theme is still set to the %admin_theme theme; consequently, the theme on this page remains unchanged. All non-administrative sections of the site, however, will show the selected %selected_theme theme by default.', [
|
||||
'%admin_theme' => $themes[$admin_theme]->info['name'],
|
||||
'%selected_theme' => $themes[$theme]->info['name'],
|
||||
]));
|
||||
$this->messenger()
|
||||
->addStatus($this->t('Please note that the administration theme is still set to the %admin_theme theme; consequently, the theme on this page remains unchanged. All non-administrative sections of the site, however, will show the selected %selected_theme theme by default.', [
|
||||
'%admin_theme' => $themes[$admin_theme]->info['name'],
|
||||
'%selected_theme' => $themes[$theme]->info['name'],
|
||||
]));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('%theme is now the default theme.', ['%theme' => $themes[$theme]->info['name']]));
|
||||
$this->messenger()->addStatus($this->t('%theme is now the default theme.', ['%theme' => $themes[$theme]->info['name']]));
|
||||
}
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('The %theme theme was not found.', ['%theme' => $theme]), 'error');
|
||||
$this->messenger()->addError($this->t('The %theme theme was not found.', ['%theme' => $theme]));
|
||||
}
|
||||
|
||||
return $this->redirect('system.themes_page');
|
||||
|
||||
@@ -36,7 +36,6 @@ class CronController extends ControllerBase {
|
||||
return new static($container->get('cron'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run Cron once.
|
||||
*
|
||||
@@ -58,10 +57,10 @@ class CronController extends ControllerBase {
|
||||
*/
|
||||
public function runManually() {
|
||||
if ($this->cron->run()) {
|
||||
drupal_set_message($this->t('Cron ran successfully.'));
|
||||
$this->messenger()->addStatus($this->t('Cron ran successfully.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('Cron run failed.'), 'error');
|
||||
$this->messenger()->addError($this->t('Cron run failed.'));
|
||||
}
|
||||
|
||||
return $this->redirect('system.status');
|
||||
|
||||
@@ -15,6 +15,13 @@ use Drupal\Component\Plugin\ConfigurablePluginInterface;
|
||||
* @ConfigEntityType(
|
||||
* id = "action",
|
||||
* label = @Translation("Action"),
|
||||
* label_collection = @Translation("Actions"),
|
||||
* label_singular = @Translation("action"),
|
||||
* label_plural = @Translation("actions"),
|
||||
* label_count = @PluralTranslation(
|
||||
* singular = "@count action",
|
||||
* plural = "@count actions",
|
||||
* ),
|
||||
* admin_permission = "administer actions",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Drupal\system\Entity;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityBase;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\system\MenuInterface;
|
||||
|
||||
/**
|
||||
@@ -11,6 +12,13 @@ use Drupal\system\MenuInterface;
|
||||
* @ConfigEntityType(
|
||||
* id = "menu",
|
||||
* label = @Translation("Menu"),
|
||||
* label_collection = @Translation("Menus"),
|
||||
* label_singular = @Translation("menu"),
|
||||
* label_plural = @Translation("menus"),
|
||||
* label_count = @PluralTranslation(
|
||||
* singular = "@count menu",
|
||||
* plural = "@count menus",
|
||||
* ),
|
||||
* handlers = {
|
||||
* "access" = "Drupal\system\MenuAccessControlHandler"
|
||||
* },
|
||||
@@ -71,4 +79,43 @@ class Menu extends ConfigEntityBase implements MenuInterface {
|
||||
return (bool) $this->locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function preDelete(EntityStorageInterface $storage, array $entities) {
|
||||
parent::preDelete($storage, $entities);
|
||||
/** @var \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager */
|
||||
$menu_link_manager = \Drupal::service('plugin.manager.menu.link');
|
||||
foreach ($entities as $menu) {
|
||||
// Delete all links from the menu.
|
||||
$menu_link_manager->deleteLinksInMenu($menu->id());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save() {
|
||||
$return = parent::save();
|
||||
\Drupal::cache('menu')->invalidateAll();
|
||||
// Invalidate the block cache to update menu-based derivatives.
|
||||
if (\Drupal::moduleHandler()->moduleExists('block')) {
|
||||
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete() {
|
||||
parent::delete();
|
||||
\Drupal::cache('menu')->invalidateAll();
|
||||
|
||||
// Invalidate the block cache to update menu-based derivatives.
|
||||
if (\Drupal::moduleHandler()->moduleExists('block')) {
|
||||
\Drupal::service('plugin.manager.block')->clearCachedDefinitions();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ class CronForm extends FormBase {
|
||||
$this->config('system.cron')
|
||||
->set('logging', $form_state->getValue('logging'))
|
||||
->save();
|
||||
drupal_set_message(t('The configuration options have been saved.'));
|
||||
$this->messenger()->addStatus(t('The configuration options have been saved.'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,10 +163,10 @@ class CronForm extends FormBase {
|
||||
*/
|
||||
public function runCron(array &$form, FormStateInterface $form_state) {
|
||||
if ($this->cron->run()) {
|
||||
drupal_set_message($this->t('Cron ran successfully.'));
|
||||
$this->messenger()->addStatus($this->t('Cron ran successfully.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('Cron run failed.'), 'error');
|
||||
$this->messenger()->addError($this->t('Cron run failed.'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ abstract class DateFormatFormBase extends EntityForm {
|
||||
$pattern = trim($form_state->getValue('date_format_pattern'));
|
||||
foreach ($this->dateFormatStorage->loadMultiple() as $format) {
|
||||
if ($format->getPattern() == $pattern && ($format->id() == $this->entity->id())) {
|
||||
drupal_set_message(t('The existing format/name combination has not been altered.'));
|
||||
$this->messenger()->addStatus($this->t('The existing format/name combination has not been altered.'));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -149,10 +149,10 @@ abstract class DateFormatFormBase extends EntityForm {
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
$status = $this->entity->save();
|
||||
if ($status == SAVED_UPDATED) {
|
||||
drupal_set_message(t('Custom date format updated.'));
|
||||
$this->messenger()->addStatus($this->t('Custom date format updated.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Custom date format added.'));
|
||||
$this->messenger()->addStatus($this->t('Custom date format added.'));
|
||||
}
|
||||
$form_state->setRedirectUrl($this->entity->urlInfo('collection'));
|
||||
}
|
||||
|
||||
@@ -174,29 +174,27 @@ class ModulesListConfirmForm extends ConfirmFormBase {
|
||||
}
|
||||
catch (PreExistingConfigException $e) {
|
||||
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
|
||||
drupal_set_message(
|
||||
$this->messenger()->addError(
|
||||
$this->formatPlural(
|
||||
count($config_objects),
|
||||
'Unable to install @extension, %config_names already exists in active configuration.',
|
||||
'Unable to install @extension, %config_names already exist in active configuration.',
|
||||
[
|
||||
'%config_names' => implode(', ', $config_objects),
|
||||
'@extension' => $this->modules['install'][$e->getExtension()]
|
||||
]),
|
||||
'error'
|
||||
'@extension' => $this->modules['install'][$e->getExtension()],
|
||||
])
|
||||
);
|
||||
return;
|
||||
}
|
||||
catch (UnmetDependenciesException $e) {
|
||||
drupal_set_message(
|
||||
$e->getTranslatedMessage($this->getStringTranslation(), $this->modules['install'][$e->getExtension()]),
|
||||
'error'
|
||||
$this->messenger()->addError(
|
||||
$e->getTranslatedMessage($this->getStringTranslation(), $this->modules['install'][$e->getExtension()])
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$module_names = array_values($this->modules['install']);
|
||||
drupal_set_message($this->formatPlural(count($module_names), 'Module %name has been enabled.', '@count modules have been enabled: %names.', [
|
||||
$this->messenger()->addStatus($this->formatPlural(count($module_names), 'Module %name has been enabled.', '@count modules have been enabled: %names.', [
|
||||
'%name' => $module_names[0],
|
||||
'%names' => implode(', ', $module_names),
|
||||
]));
|
||||
|
||||
@@ -27,7 +27,7 @@ class ModulesListExperimentalConfirmForm extends ModulesListConfirmForm {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildMessageList() {
|
||||
drupal_set_message($this->t('<a href=":url">Experimental modules</a> are provided for testing purposes only. Use at your own risk.', [':url' => 'https://www.drupal.org/core/experimental']), 'warning');
|
||||
$this->messenger()->addWarning($this->t('<a href=":url">Experimental modules</a> are provided for testing purposes only. Use at your own risk.', [':url' => 'https://www.drupal.org/core/experimental']));
|
||||
|
||||
$items = parent::buildMessageList();
|
||||
// Add the list of experimental modules after any other messages.
|
||||
|
||||
@@ -450,30 +450,28 @@ class ModulesListForm extends FormBase {
|
||||
try {
|
||||
$this->moduleInstaller->install(array_keys($modules['install']));
|
||||
$module_names = array_values($modules['install']);
|
||||
drupal_set_message($this->formatPlural(count($module_names), 'Module %name has been enabled.', '@count modules have been enabled: %names.', [
|
||||
$this->messenger()->addStatus($this->formatPlural(count($module_names), 'Module %name has been enabled.', '@count modules have been enabled: %names.', [
|
||||
'%name' => $module_names[0],
|
||||
'%names' => implode(', ', $module_names),
|
||||
]));
|
||||
}
|
||||
catch (PreExistingConfigException $e) {
|
||||
$config_objects = $e->flattenConfigObjects($e->getConfigObjects());
|
||||
drupal_set_message(
|
||||
$this->messenger()->addError(
|
||||
$this->formatPlural(
|
||||
count($config_objects),
|
||||
'Unable to install @extension, %config_names already exists in active configuration.',
|
||||
'Unable to install @extension, %config_names already exist in active configuration.',
|
||||
[
|
||||
'%config_names' => implode(', ', $config_objects),
|
||||
'@extension' => $modules['install'][$e->getExtension()]
|
||||
]),
|
||||
'error'
|
||||
'@extension' => $modules['install'][$e->getExtension()],
|
||||
])
|
||||
);
|
||||
return;
|
||||
}
|
||||
catch (UnmetDependenciesException $e) {
|
||||
drupal_set_message(
|
||||
$e->getTranslatedMessage($this->getStringTranslation(), $modules['install'][$e->getExtension()]),
|
||||
'error'
|
||||
$this->messenger()->addError(
|
||||
$e->getTranslatedMessage($this->getStringTranslation(), $modules['install'][$e->getExtension()])
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ class ModulesUninstallConfirmForm extends ConfirmFormBase {
|
||||
|
||||
// Prevent this page from showing when the module list is empty.
|
||||
if (empty($this->modules)) {
|
||||
drupal_set_message($this->t('The selected modules could not be uninstalled, either due to a website problem or due to the uninstall confirmation form timing out. Please try again.'), 'error');
|
||||
$this->messenger()->addError($this->t('The selected modules could not be uninstalled, either due to a website problem or due to the uninstall confirmation form timing out. Please try again.'));
|
||||
return $this->redirect('system.modules_uninstall');
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ class ModulesUninstallConfirmForm extends ConfirmFormBase {
|
||||
// Uninstall the modules.
|
||||
$this->moduleInstaller->uninstall($this->modules);
|
||||
|
||||
drupal_set_message($this->t('The selected modules have been uninstalled.'));
|
||||
$this->messenger()->addStatus($this->t('The selected modules have been uninstalled.'));
|
||||
$form_state->setRedirectUrl($this->getCancelUrl());
|
||||
}
|
||||
|
||||
|
||||
@@ -116,8 +116,6 @@ class ModulesUninstallForm extends FormBase {
|
||||
return $form;
|
||||
}
|
||||
|
||||
$profile = drupal_get_profile();
|
||||
|
||||
// Sort all modules by their name.
|
||||
uasort($uninstallable, 'system_sort_modules_by_info_name');
|
||||
$validation_reasons = $this->moduleInstaller->validateUninstall(array_keys($uninstallable));
|
||||
@@ -142,10 +140,9 @@ class ModulesUninstallForm extends FormBase {
|
||||
$form['uninstall'][$module->getName()]['#disabled'] = TRUE;
|
||||
}
|
||||
// All modules which depend on this one must be uninstalled first, before
|
||||
// we can allow this module to be uninstalled. (The installation profile
|
||||
// is excluded from this list.)
|
||||
// we can allow this module to be uninstalled.
|
||||
foreach (array_keys($module->required_by) as $dependent) {
|
||||
if ($dependent != $profile && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) {
|
||||
if (drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) {
|
||||
$name = isset($modules[$dependent]->info['name']) ? $modules[$dependent]->info['name'] : $dependent;
|
||||
$form['modules'][$module->getName()]['#required_by'][] = $name;
|
||||
$form['uninstall'][$module->getName()]['#disabled'] = TRUE;
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
namespace Drupal\system\Form;
|
||||
|
||||
use Drupal\Core\Asset\AssetCollectionOptimizerInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Datetime\DateFormatterInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
@@ -37,6 +39,13 @@ class PerformanceForm extends ConfigFormBase {
|
||||
*/
|
||||
protected $jsCollectionOptimizer;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* Constructs a PerformanceForm object.
|
||||
*
|
||||
@@ -48,13 +57,16 @@ class PerformanceForm extends ConfigFormBase {
|
||||
* The CSS asset collection optimizer service.
|
||||
* @param \Drupal\Core\Asset\AssetCollectionOptimizerInterface $js_collection_optimizer
|
||||
* The JavaScript asset collection optimizer service.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, DateFormatterInterface $date_formatter, AssetCollectionOptimizerInterface $css_collection_optimizer, AssetCollectionOptimizerInterface $js_collection_optimizer) {
|
||||
public function __construct(ConfigFactoryInterface $config_factory, DateFormatterInterface $date_formatter, AssetCollectionOptimizerInterface $css_collection_optimizer, AssetCollectionOptimizerInterface $js_collection_optimizer, ModuleHandlerInterface $module_handler) {
|
||||
parent::__construct($config_factory);
|
||||
|
||||
$this->dateFormatter = $date_formatter;
|
||||
$this->cssCollectionOptimizer = $css_collection_optimizer;
|
||||
$this->jsCollectionOptimizer = $js_collection_optimizer;
|
||||
$this->moduleHandler = $module_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,7 +77,8 @@ class PerformanceForm extends ConfigFormBase {
|
||||
$container->get('config.factory'),
|
||||
$container->get('date.formatter'),
|
||||
$container->get('asset.css.collection_optimizer'),
|
||||
$container->get('asset.js.collection_optimizer')
|
||||
$container->get('asset.js.collection_optimizer'),
|
||||
$container->get('module_handler')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -107,7 +120,6 @@ class PerformanceForm extends ConfigFormBase {
|
||||
'#type' => 'details',
|
||||
'#title' => t('Caching'),
|
||||
'#open' => TRUE,
|
||||
'#description' => $this->t('Note: Drupal provides an internal page cache module that is recommended for small to medium-sized websites.'),
|
||||
];
|
||||
// Identical options to the ones for block caching.
|
||||
// @see \Drupal\Core\Block\BlockBase::buildConfigurationForm()
|
||||
@@ -116,10 +128,14 @@ class PerformanceForm extends ConfigFormBase {
|
||||
$period[0] = '<' . t('no caching') . '>';
|
||||
$form['caching']['page_cache_maximum_age'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => t('Page cache maximum age'),
|
||||
'#title' => t('Browser and proxy cache maximum age'),
|
||||
'#default_value' => $config->get('cache.page.max_age'),
|
||||
'#options' => $period,
|
||||
'#description' => t('The maximum time a page can be cached by browsers and proxies. This is used as the value for max-age in Cache-Control headers.'),
|
||||
'#description' => t('This is used as the value for max-age in Cache-Control headers.'),
|
||||
];
|
||||
$form['caching']['internal_page_cache'] = [
|
||||
'#markup' => $this->t('Drupal provides an <a href=":module_enable">Internal Page Cache module</a> that is recommended for small to medium-sized websites.', [':module_enable' => Url::fromRoute('system.modules_list')->toString()]),
|
||||
'#access' => !$this->moduleHandler->moduleExists('page_cache'),
|
||||
];
|
||||
|
||||
$directory = 'public://';
|
||||
@@ -174,7 +190,7 @@ class PerformanceForm extends ConfigFormBase {
|
||||
*/
|
||||
public function submitCacheClear(array &$form, FormStateInterface $form_state) {
|
||||
drupal_flush_all_caches();
|
||||
drupal_set_message(t('Caches cleared.'));
|
||||
$this->messenger()->addStatus($this->t('Caches cleared.'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ class PrepareModulesEntityUninstallForm extends ConfirmFormBase {
|
||||
'@entity_type_singular' => $entity_type->getSingularLabel(),
|
||||
'@entity_type_plural' => $entity_type->getPluralLabel(),
|
||||
]
|
||||
)
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ class PrepareModulesEntityUninstallForm extends ConfirmFormBase {
|
||||
*/
|
||||
public static function moduleBatchFinished($success, $results, $operations) {
|
||||
$entity_type_plural = \Drupal::entityTypeManager()->getDefinition($results['entity_type_id'])->getPluralLabel();
|
||||
drupal_set_message(t('All @entity_type_plural have been deleted.', ['@entity_type_plural' => $entity_type_plural]));
|
||||
\Drupal::messenger()->addStatus(t('All @entity_type_plural have been deleted.', ['@entity_type_plural' => $entity_type_plural]));
|
||||
|
||||
return new RedirectResponse(Url::fromRoute('system.modules_uninstall')->setAbsolute()->toString());
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ class RegionalForm extends ConfigFormBase {
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Remind users at login if their time zone is not set'),
|
||||
'#default_value' => $system_date->get('timezone.user.warn'),
|
||||
'#description' => t('Only applied if users may set their own time zone.')
|
||||
'#description' => t('Only applied if users may set their own time zone.'),
|
||||
];
|
||||
|
||||
$form['timezone']['configurable_timezones_wrapper']['user_default_timezone'] = [
|
||||
@@ -137,7 +137,7 @@ class RegionalForm extends ConfigFormBase {
|
||||
DRUPAL_USER_TIMEZONE_EMPTY => t('Empty time zone'),
|
||||
DRUPAL_USER_TIMEZONE_SELECT => t('Users may set their own time zone at registration'),
|
||||
],
|
||||
'#description' => t('Only applied if users may set their own time zone.')
|
||||
'#description' => t('Only applied if users may set their own time zone.'),
|
||||
];
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
|
||||
@@ -35,7 +35,7 @@ class RssFeedsForm extends ConfigFormBase {
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Feed description'),
|
||||
'#default_value' => $rss_config->get('channel.description'),
|
||||
'#description' => t('Description of your site, included in each feed.')
|
||||
'#description' => t('Description of your site, included in each feed.'),
|
||||
];
|
||||
$options = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30];
|
||||
$form['feed_default_items'] = [
|
||||
@@ -43,7 +43,7 @@ class RssFeedsForm extends ConfigFormBase {
|
||||
'#title' => t('Number of items in each feed'),
|
||||
'#default_value' => $rss_config->get('items.limit'),
|
||||
'#options' => array_combine($options, $options),
|
||||
'#description' => t('Default number of items to include in each feed.')
|
||||
'#description' => t('Default number of items to include in each feed.'),
|
||||
];
|
||||
$form['feed_view_mode'] = [
|
||||
'#type' => 'select',
|
||||
@@ -54,7 +54,7 @@ class RssFeedsForm extends ConfigFormBase {
|
||||
'teaser' => t('Titles plus teaser'),
|
||||
'fulltext' => t('Full text'),
|
||||
],
|
||||
'#description' => t('Global setting for the default display of content items in each feed.')
|
||||
'#description' => t('Global setting for the default display of content items in each feed.'),
|
||||
];
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
|
||||
@@ -56,6 +56,7 @@ class SiteMaintenanceModeForm extends ConfigFormBase {
|
||||
$container->get('user.permissions')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -136,11 +136,11 @@ class ThemeSettingsForm extends ConfigFormBase {
|
||||
|
||||
$form['var'] = [
|
||||
'#type' => 'hidden',
|
||||
'#value' => $var
|
||||
'#value' => $var,
|
||||
];
|
||||
$form['config_key'] = [
|
||||
'#type' => 'hidden',
|
||||
'#value' => $config_key
|
||||
'#value' => $config_key,
|
||||
];
|
||||
|
||||
// Toggle settings
|
||||
@@ -377,22 +377,23 @@ class ThemeSettingsForm extends ConfigFormBase {
|
||||
parent::validateForm($form, $form_state);
|
||||
|
||||
if ($this->moduleHandler->moduleExists('file')) {
|
||||
$validators = ['file_validate_is_image' => []];
|
||||
|
||||
// Check for a new uploaded logo.
|
||||
$file = _file_save_upload_from_form($form['logo']['settings']['logo_upload'], $form_state, 0);
|
||||
if ($file) {
|
||||
// Put the temporary file in form_values so we can save it on submit.
|
||||
$form_state->setValue('logo_upload', $file);
|
||||
if (isset($form['logo'])) {
|
||||
$file = _file_save_upload_from_form($form['logo']['settings']['logo_upload'], $form_state, 0);
|
||||
if ($file) {
|
||||
// Put the temporary file in form_values so we can save it on submit.
|
||||
$form_state->setValue('logo_upload', $file);
|
||||
}
|
||||
}
|
||||
|
||||
$validators = ['file_validate_extensions' => ['ico png gif jpg jpeg apng svg']];
|
||||
|
||||
// Check for a new uploaded favicon.
|
||||
$file = _file_save_upload_from_form($form['favicon']['settings']['favicon_upload'], $form_state, 0);
|
||||
if ($file) {
|
||||
// Put the temporary file in form_values so we can save it on submit.
|
||||
$form_state->setValue('favicon_upload', $file);
|
||||
if (isset($form['favicon'])) {
|
||||
$file = _file_save_upload_from_form($form['favicon']['settings']['favicon_upload'], $form_state, 0);
|
||||
if ($file) {
|
||||
// Put the temporary file in form_values so we can save it on submit.
|
||||
$form_state->setValue('favicon_upload', $file);
|
||||
}
|
||||
}
|
||||
|
||||
// When intending to use the default logo, unset the logo_path.
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace Drupal\system;
|
||||
|
||||
use Drupal\Component\Transliteration\TransliterationInterface;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Access\CsrfTokenGenerator;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
@@ -73,7 +72,7 @@ class MachineNameController implements ContainerInjectionInterface {
|
||||
|
||||
$transliterated = $this->transliteration->transliterate($text, $langcode, '_');
|
||||
if ($lowercase) {
|
||||
$transliterated = Unicode::strtolower($transliterated);
|
||||
$transliterated = mb_strtolower($transliterated);
|
||||
}
|
||||
|
||||
if (isset($replace_pattern) && isset($replace)) {
|
||||
|
||||
@@ -9,7 +9,7 @@ use Drupal\Core\Cache\Cache;
|
||||
/**
|
||||
* Provides a block to display the messages.
|
||||
*
|
||||
* @see drupal_set_message()
|
||||
* @see @see \Drupal\Core\Messenger\MessengerInterface
|
||||
*
|
||||
* @Block(
|
||||
* id = "system_messages_block",
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Drupal\system\Plugin\Condition;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Condition\ConditionPluginBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Path\AliasManagerInterface;
|
||||
@@ -139,7 +138,7 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI
|
||||
public function evaluate() {
|
||||
// Convert path to lowercase. This allows comparison of the same path
|
||||
// with different case. Ex: /Page, /page, /PAGE.
|
||||
$pages = Unicode::strtolower($this->configuration['pages']);
|
||||
$pages = mb_strtolower($this->configuration['pages']);
|
||||
if (!$pages) {
|
||||
return TRUE;
|
||||
}
|
||||
@@ -149,7 +148,7 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI
|
||||
$path = $this->currentPath->getPath($request);
|
||||
// Do not trim a trailing slash if that is the complete path.
|
||||
$path = $path === '/' ? $path : rtrim($path, '/');
|
||||
$path_alias = Unicode::strtolower($this->aliasManager->getAliasByPath($path));
|
||||
$path_alias = mb_strtolower($this->aliasManager->getAliasByPath($path));
|
||||
|
||||
return $this->pathMatcher->matchPath($path_alias, $pages) || (($path != $path_alias) && $this->pathMatcher->matchPath($path, $pages));
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace Drupal\system\Plugin\ImageToolkit;
|
||||
|
||||
use Drupal\Component\Utility\Color;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\ImageToolkit\ImageToolkitBase;
|
||||
@@ -395,7 +394,7 @@ class GDToolkit extends ImageToolkitBase {
|
||||
foreach (static::supportedTypes() as $image_type) {
|
||||
// @todo Automatically fetch possible extensions for each mime type.
|
||||
// @see https://www.drupal.org/node/2311679
|
||||
$extension = Unicode::strtolower(image_type_to_extension($image_type, FALSE));
|
||||
$extension = mb_strtolower(image_type_to_extension($image_type, FALSE));
|
||||
$extensions[] = $extension;
|
||||
// Add some known similar extensions.
|
||||
if ($extension === 'jpeg') {
|
||||
|
||||
@@ -20,6 +20,16 @@ class ScaleAndCrop extends GDImageToolkitOperationBase {
|
||||
*/
|
||||
protected function arguments() {
|
||||
return [
|
||||
'x' => [
|
||||
'description' => 'The horizontal offset for the start of the crop, in pixels',
|
||||
'required' => FALSE,
|
||||
'default' => NULL,
|
||||
],
|
||||
'y' => [
|
||||
'description' => 'The vertical offset for the start the crop, in pixels',
|
||||
'required' => FALSE,
|
||||
'default' => NULL,
|
||||
],
|
||||
'width' => [
|
||||
'description' => 'The target width, in pixels',
|
||||
],
|
||||
@@ -38,8 +48,12 @@ class ScaleAndCrop extends GDImageToolkitOperationBase {
|
||||
|
||||
$scaleFactor = max($arguments['width'] / $actualWidth, $arguments['height'] / $actualHeight);
|
||||
|
||||
$arguments['x'] = (int) round(($actualWidth * $scaleFactor - $arguments['width']) / 2);
|
||||
$arguments['y'] = (int) round(($actualHeight * $scaleFactor - $arguments['height']) / 2);
|
||||
$arguments['x'] = isset($arguments['x']) ?
|
||||
(int) round($arguments['x']) :
|
||||
(int) round(($actualWidth * $scaleFactor - $arguments['width']) / 2);
|
||||
$arguments['y'] = isset($arguments['y']) ?
|
||||
(int) round($arguments['y']) :
|
||||
(int) round(($actualHeight * $scaleFactor - $arguments['height']) / 2);
|
||||
$arguments['resize'] = [
|
||||
'width' => (int) round($actualWidth * $scaleFactor),
|
||||
'height' => (int) round($actualHeight * $scaleFactor),
|
||||
|
||||
@@ -14,6 +14,7 @@ use Drupal\migrate\Row;
|
||||
* )
|
||||
*/
|
||||
class TimeZone extends ProcessPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Plugin\migrate\source;
|
||||
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
|
||||
|
||||
/**
|
||||
* Gets system data for a legacy extension.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "extension",
|
||||
* source_module = "system"
|
||||
* )
|
||||
*/
|
||||
class Extension extends DrupalSqlBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function query() {
|
||||
$query = $this->select('system', 's')
|
||||
->fields('s');
|
||||
|
||||
if (isset($this->configuration['name'])) {
|
||||
$query->condition('name', (array) $this->configuration['name'], 'IN');
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields() {
|
||||
$fields = [
|
||||
'filename' => $this->t('Filename'),
|
||||
'name' => $this->t('Name'),
|
||||
'type' => $this->t('Type'),
|
||||
'owner' => $this->t('Owner'),
|
||||
'status' => $this->t('Status'),
|
||||
'throttle' => $this->t('Throttle'),
|
||||
'bootstrap' => $this->t('Bootstrap'),
|
||||
'schema_version' => $this->t('Schema version'),
|
||||
'weight' => $this->t('Weight'),
|
||||
'info' => $this->t('Information array'),
|
||||
];
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
$row->setSourceProperty('info', unserialize($row->getSourceProperty('info')));
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIds() {
|
||||
$ids['name']['type'] = 'string';
|
||||
return $ids;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -72,6 +72,9 @@ class SystemConfigSubscriber implements EventSubscriberInterface {
|
||||
* The config import event.
|
||||
*/
|
||||
public function onConfigImporterValidateSiteUUID(ConfigImporterEvent $event) {
|
||||
if (!$event->getConfigImporter()->getStorageComparer()->getSourceStorage()->exists('system.site')) {
|
||||
$event->getConfigImporter()->logError($this->t('This import does not contain system.site configuration, so has been rejected.'));
|
||||
}
|
||||
if (!$event->getConfigImporter()->getStorageComparer()->validateSiteUuid()) {
|
||||
$event->getConfigImporter()->logError($this->t('Site UUID in source storage does not match the target storage.'));
|
||||
}
|
||||
|
||||
@@ -152,7 +152,8 @@ class SystemManager {
|
||||
* hidden, so we supply the contents of the block.
|
||||
*
|
||||
* @return array
|
||||
* A render array suitable for drupal_render.
|
||||
* A render array suitable for
|
||||
* \Drupal\Core\Render\RendererInterface::render().
|
||||
*/
|
||||
public function getBlockContents() {
|
||||
// We hard-code the menu name here since otherwise a link in the tools menu
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Ajax;
|
||||
|
||||
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
|
||||
use Drupal\Core\Form\FormBuilderInterface;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Tests the usage of form caching for AJAX forms.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class AjaxFormCacheTest extends AjaxTestBase {
|
||||
|
||||
/**
|
||||
* Tests the usage of form cache for AJAX forms.
|
||||
*/
|
||||
public function testFormCacheUsage() {
|
||||
/** @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $key_value_expirable */
|
||||
$key_value_expirable = \Drupal::service('keyvalue.expirable')->get('form');
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
// Ensure that the cache is empty.
|
||||
$this->assertEqual(0, count($key_value_expirable->getAll()));
|
||||
|
||||
// Visit an AJAX form that is not cached, 3 times.
|
||||
$uncached_form_url = Url::fromRoute('ajax_forms_test.commands_form');
|
||||
$this->drupalGet($uncached_form_url);
|
||||
$this->drupalGet($uncached_form_url);
|
||||
$this->drupalGet($uncached_form_url);
|
||||
|
||||
// The number of cache entries should not have changed.
|
||||
$this->assertEqual(0, count($key_value_expirable->getAll()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests AJAX forms in blocks.
|
||||
*/
|
||||
public function testBlockForms() {
|
||||
$this->container->get('module_installer')->install(['block', 'search']);
|
||||
$this->rebuildContainer();
|
||||
$this->container->get('router.builder')->rebuild();
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
$this->drupalPlaceBlock('search_form_block', ['weight' => -5]);
|
||||
$this->drupalPlaceBlock('ajax_forms_test_block');
|
||||
|
||||
$this->drupalGet('');
|
||||
$this->drupalPostAjaxForm(NULL, ['test1' => 'option1'], 'test1');
|
||||
$this->assertOptionSelectedWithDrupalSelector('edit-test1', 'option1');
|
||||
$this->assertOptionWithDrupalSelector('edit-test1', 'option3');
|
||||
$this->drupalPostForm(NULL, ['test1' => 'option1'], 'Submit');
|
||||
$this->assertText('Submission successful.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests AJAX forms on pages with a query string.
|
||||
*/
|
||||
public function testQueryString() {
|
||||
$this->container->get('module_installer')->install(['block']);
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
$this->drupalPlaceBlock('ajax_forms_test_block');
|
||||
|
||||
$url = Url::fromRoute('entity.user.canonical', ['user' => $this->rootUser->id()], ['query' => ['foo' => 'bar']]);
|
||||
$this->drupalGet($url);
|
||||
$this->drupalPostAjaxForm(NULL, ['test1' => 'option1'], 'test1');
|
||||
$url->setOption('query', [
|
||||
'foo' => 'bar',
|
||||
FormBuilderInterface::AJAX_FORM_REQUEST => 1,
|
||||
MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax',
|
||||
]);
|
||||
$this->assertUrl($url);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Ajax;
|
||||
|
||||
/**
|
||||
* Tests that form elements in groups work correctly with AJAX.
|
||||
*
|
||||
* @group Ajax
|
||||
*/
|
||||
class AjaxInGroupTest extends AjaxTestBase {
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser(['access content']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits forms with select and checkbox elements via Ajax.
|
||||
*/
|
||||
public function testSimpleAjaxFormValue() {
|
||||
$this->drupalGet('/ajax_forms_test_get_form');
|
||||
$this->assertText('Test group');
|
||||
$this->assertText('AJAX checkbox in a group');
|
||||
|
||||
$this->drupalPostAjaxForm(NULL, ['checkbox_in_group' => TRUE], 'checkbox_in_group');
|
||||
$this->assertText('Test group');
|
||||
$this->assertText('AJAX checkbox in a group');
|
||||
$this->assertText('AJAX checkbox in a nested group');
|
||||
$this->assertText('Another AJAX checkbox in a nested group');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,6 +29,7 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
* @group Ajax
|
||||
*/
|
||||
class CommandsTest extends AjaxTestBase {
|
||||
|
||||
/**
|
||||
* Tests the various Ajax Commands.
|
||||
*/
|
||||
|
||||
@@ -114,7 +114,7 @@ class DialogTest extends AjaxTestBase {
|
||||
], [], 'ajax-test/dialog-contents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_dialog']], [], NULL, [
|
||||
'submit' => [
|
||||
'dialogOptions[target]' => 'ajax-test-dialog-wrapper-1',
|
||||
]
|
||||
],
|
||||
]);
|
||||
$this->assertEqual($normal_expected_response, $ajax_result[3], 'Normal dialog JSON response matches.');
|
||||
|
||||
@@ -126,7 +126,7 @@ class DialogTest extends AjaxTestBase {
|
||||
'textfield' => 'test',
|
||||
], [], 'ajax-test/dialog-contents', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_dialog']], [], NULL, [
|
||||
// Don't send a target.
|
||||
'submit' => []
|
||||
'submit' => [],
|
||||
]);
|
||||
// Make sure the selector ID starts with the right string.
|
||||
$this->assert(strpos($ajax_result[3]['selector'], $no_target_expected_response['selector']) === 0, 'Selector starts with right string.');
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Drupal\system\Tests\Ajax;
|
||||
* @group Ajax
|
||||
*/
|
||||
class ElementValidationTest extends AjaxTestBase {
|
||||
|
||||
/**
|
||||
* Tries to post an Ajax change to a form that has a validated element.
|
||||
*
|
||||
|
||||
@@ -10,6 +10,7 @@ use Drupal\Core\Ajax\DataCommand;
|
||||
* @group Ajax
|
||||
*/
|
||||
class FormValuesTest extends AjaxTestBase {
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ use Drupal\Core\Asset\AttachedAssets;
|
||||
* @group Ajax
|
||||
*/
|
||||
class FrameworkTest extends AjaxTestBase {
|
||||
|
||||
/**
|
||||
* Verifies the Ajax rendering of a command in the settings.
|
||||
*/
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Bootstrap;
|
||||
|
||||
use Drupal\Core\DependencyInjection\Container;
|
||||
|
||||
/**
|
||||
* Container base class which triggers an error.
|
||||
*/
|
||||
class ErrorContainer extends Container {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE) {
|
||||
if ($id === 'http_kernel') {
|
||||
// Enforce a recoverable error.
|
||||
$callable = function (ErrorContainer $container) {
|
||||
};
|
||||
$callable(1);
|
||||
}
|
||||
else {
|
||||
return parent::get($id, $invalidBehavior);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Bootstrap;
|
||||
|
||||
use Drupal\Core\DependencyInjection\Container;
|
||||
|
||||
/**
|
||||
* Base container which throws an exception.
|
||||
*/
|
||||
class ExceptionContainer extends Container {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE) {
|
||||
if ($id === 'http_kernel') {
|
||||
throw new \Exception('Thrown exception during Container::get');
|
||||
}
|
||||
else {
|
||||
return parent::get($id, $invalidBehavior);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@ namespace Drupal\system\Tests\Cache;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
|
||||
/**
|
||||
* Provides helper methods for page cache tags tests.
|
||||
@@ -47,7 +47,7 @@ abstract class PageCacheTagsTestBase extends WebTestBase {
|
||||
*/
|
||||
protected function verifyPageCache(Url $url, $hit_or_miss, $tags = FALSE) {
|
||||
$this->drupalGet($url);
|
||||
$message = SafeMarkup::format('Page cache @hit_or_miss for %path.', ['@hit_or_miss' => $hit_or_miss, '%path' => $url->toString()]);
|
||||
$message = new FormattableMarkup('Page cache @hit_or_miss for %path.', ['@hit_or_miss' => $hit_or_miss, '%path' => $url->toString()]);
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), $hit_or_miss, $message);
|
||||
|
||||
if ($hit_or_miss === 'HIT' && is_array($tags)) {
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Common;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Make sure that attaching feeds works correctly with various constructs.
|
||||
*
|
||||
* @group Common
|
||||
*/
|
||||
class AddFeedTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Tests attaching feeds with paths, URLs, and titles.
|
||||
*/
|
||||
public function testBasicFeedAddNoTitle() {
|
||||
$path = $this->randomMachineName(12);
|
||||
$external_url = 'http://' . $this->randomMachineName(12) . '/' . $this->randomMachineName(12);
|
||||
$fully_qualified_local_url = Url::fromUri('base:' . $this->randomMachineName(12), ['absolute' => TRUE])->toString();
|
||||
|
||||
$path_for_title = $this->randomMachineName(12);
|
||||
$external_for_title = 'http://' . $this->randomMachineName(12) . '/' . $this->randomMachineName(12);
|
||||
$fully_qualified_for_title = Url::fromUri('base:' . $this->randomMachineName(12), ['absolute' => TRUE])->toString();
|
||||
|
||||
$urls = [
|
||||
'path without title' => [
|
||||
'url' => Url::fromUri('base:' . $path, ['absolute' => TRUE])->toString(),
|
||||
'title' => '',
|
||||
],
|
||||
'external URL without title' => [
|
||||
'url' => $external_url,
|
||||
'title' => '',
|
||||
],
|
||||
'local URL without title' => [
|
||||
'url' => $fully_qualified_local_url,
|
||||
'title' => '',
|
||||
],
|
||||
'path with title' => [
|
||||
'url' => Url::fromUri('base:' . $path_for_title, ['absolute' => TRUE])->toString(),
|
||||
'title' => $this->randomMachineName(12),
|
||||
],
|
||||
'external URL with title' => [
|
||||
'url' => $external_for_title,
|
||||
'title' => $this->randomMachineName(12),
|
||||
],
|
||||
'local URL with title' => [
|
||||
'url' => $fully_qualified_for_title,
|
||||
'title' => $this->randomMachineName(12),
|
||||
],
|
||||
];
|
||||
|
||||
$build = [];
|
||||
foreach ($urls as $feed_info) {
|
||||
$build['#attached']['feed'][] = [$feed_info['url'], $feed_info['title']];
|
||||
}
|
||||
|
||||
// Use the bare HTML page renderer to render our links.
|
||||
$renderer = $this->container->get('bare_html_page_renderer');
|
||||
$response = $renderer->renderBarePage($build, '', 'maintenance_page');
|
||||
// Glean the content from the response object.
|
||||
$this->setRawContent($response->getContent());
|
||||
// Assert that the content contains the RSS links we specified.
|
||||
foreach ($urls as $description => $feed_info) {
|
||||
$this->assertPattern($this->urlToRSSLinkPattern($feed_info['url'], $feed_info['title']), format_string('Found correct feed header for %description', ['%description' => $description]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a pattern representing the RSS feed in the page.
|
||||
*/
|
||||
public function urlToRSSLinkPattern($url, $title = '') {
|
||||
// Escape any regular expression characters in the URL ('?' is the worst).
|
||||
$url = preg_replace('/([+?.*])/', '[$0]', $url);
|
||||
$generated_pattern = '%<link +href="' . $url . '" +rel="alternate" +title="' . $title . '" +type="application/rss.xml" */>%';
|
||||
return $generated_pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that special characters are correctly escaped.
|
||||
*
|
||||
* @see https://www.drupal.org/node/1211668
|
||||
*/
|
||||
public function testFeedIconEscaping() {
|
||||
$variables = [
|
||||
'#theme' => 'feed_icon',
|
||||
'#url' => 'node',
|
||||
'#title' => '<>&"\'',
|
||||
];
|
||||
$text = \Drupal::service('renderer')->renderRoot($variables);
|
||||
$this->assertEqual(trim(strip_tags($text)), 'Subscribe to <>&"'', 'feed_icon template escapes reserved HTML characters.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Common;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests alteration of arguments passed to \Drupal::moduleHandler->alter().
|
||||
*
|
||||
* @group Common
|
||||
*/
|
||||
class AlterTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['block', 'common_test'];
|
||||
|
||||
/**
|
||||
* Tests if the theme has been altered.
|
||||
*/
|
||||
public function testDrupalAlter() {
|
||||
// This test depends on Bartik, so make sure that it is always the current
|
||||
// active theme.
|
||||
\Drupal::service('theme_handler')->install(['bartik']);
|
||||
\Drupal::theme()->setActiveTheme(\Drupal::service('theme.initialization')->initTheme('bartik'));
|
||||
|
||||
$array = ['foo' => 'bar'];
|
||||
$entity = new \stdClass();
|
||||
$entity->foo = 'bar';
|
||||
|
||||
// Verify alteration of a single argument.
|
||||
$array_copy = $array;
|
||||
$array_expected = ['foo' => 'Drupal theme'];
|
||||
\Drupal::moduleHandler()->alter('drupal_alter', $array_copy);
|
||||
\Drupal::theme()->alter('drupal_alter', $array_copy);
|
||||
$this->assertEqual($array_copy, $array_expected, 'Single array was altered.');
|
||||
|
||||
$entity_copy = clone $entity;
|
||||
$entity_expected = clone $entity;
|
||||
$entity_expected->foo = 'Drupal theme';
|
||||
\Drupal::moduleHandler()->alter('drupal_alter', $entity_copy);
|
||||
\Drupal::theme()->alter('drupal_alter', $entity_copy);
|
||||
$this->assertEqual($entity_copy, $entity_expected, 'Single object was altered.');
|
||||
|
||||
// Verify alteration of multiple arguments.
|
||||
$array_copy = $array;
|
||||
$array_expected = ['foo' => 'Drupal theme'];
|
||||
$entity_copy = clone $entity;
|
||||
$entity_expected = clone $entity;
|
||||
$entity_expected->foo = 'Drupal theme';
|
||||
$array2_copy = $array;
|
||||
$array2_expected = ['foo' => 'Drupal theme'];
|
||||
\Drupal::moduleHandler()->alter('drupal_alter', $array_copy, $entity_copy, $array2_copy);
|
||||
\Drupal::theme()->alter('drupal_alter', $array_copy, $entity_copy, $array2_copy);
|
||||
$this->assertEqual($array_copy, $array_expected, 'First argument to \Drupal::moduleHandler->alter() was altered.');
|
||||
$this->assertEqual($entity_copy, $entity_expected, 'Second argument to \Drupal::moduleHandler->alter() was altered.');
|
||||
$this->assertEqual($array2_copy, $array2_expected, 'Third argument to \Drupal::moduleHandler->alter() was altered.');
|
||||
|
||||
// Verify alteration order when passing an array of types to \Drupal::moduleHandler->alter().
|
||||
// common_test_module_implements_alter() places 'block' implementation after
|
||||
// other modules.
|
||||
$array_copy = $array;
|
||||
$array_expected = ['foo' => 'Drupal block theme'];
|
||||
\Drupal::moduleHandler()->alter(['drupal_alter', 'drupal_alter_foo'], $array_copy);
|
||||
\Drupal::theme()->alter(['drupal_alter', 'drupal_alter_foo'], $array_copy);
|
||||
$this->assertEqual($array_copy, $array_expected, 'hook_TYPE_alter() implementations ran in correct order.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Common;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Verifies that bubbleable metadata of early rendering is not lost.
|
||||
*
|
||||
* @group Common
|
||||
*/
|
||||
class EarlyRenderingControllerTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $dumpHeaders = TRUE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['system', 'early_rendering_controller_test'];
|
||||
|
||||
/**
|
||||
* Tests theme preprocess functions being able to attach assets.
|
||||
*/
|
||||
public function testEarlyRendering() {
|
||||
// Render array: non-early & early.
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.render_array'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('Hello world!');
|
||||
$this->assertCacheTag('foo');
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.render_array.early'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('Hello world!');
|
||||
$this->assertCacheTag('foo');
|
||||
|
||||
// AjaxResponse: non-early & early.
|
||||
// @todo Add cache tags assertion when AjaxResponse is made cacheable in
|
||||
// https://www.drupal.org/node/956186.
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.ajax_response'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('Hello world!');
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.ajax_response.early'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('Hello world!');
|
||||
|
||||
// Basic Response object: non-early & early.
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.response'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('Hello world!');
|
||||
$this->assertNoCacheTag('foo');
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.response.early'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('Hello world!');
|
||||
$this->assertNoCacheTag('foo');
|
||||
|
||||
// Response object with attachments: non-early & early.
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.response-with-attachments'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('Hello world!');
|
||||
$this->assertNoCacheTag('foo');
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.response-with-attachments.early'));
|
||||
$this->assertResponse(500);
|
||||
$this->assertRaw('The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: Drupal\early_rendering_controller_test\AttachmentsTestResponse.');
|
||||
|
||||
// Cacheable Response object: non-early & early.
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.cacheable-response'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('Hello world!');
|
||||
$this->assertNoCacheTag('foo');
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.cacheable-response.early'));
|
||||
$this->assertResponse(500);
|
||||
$this->assertRaw('The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: Drupal\early_rendering_controller_test\CacheableTestResponse.');
|
||||
|
||||
// Basic domain object: non-early & early.
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.domain-object'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('TestDomainObject');
|
||||
$this->assertNoCacheTag('foo');
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.domain-object.early'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('TestDomainObject');
|
||||
$this->assertNoCacheTag('foo');
|
||||
|
||||
// Basic domain object with attachments: non-early & early.
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.domain-object-with-attachments'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('AttachmentsTestDomainObject');
|
||||
$this->assertNoCacheTag('foo');
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.domain-object-with-attachments.early'));
|
||||
$this->assertResponse(500);
|
||||
$this->assertRaw('The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: Drupal\early_rendering_controller_test\AttachmentsTestDomainObject.');
|
||||
|
||||
// Cacheable Response object: non-early & early.
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.cacheable-domain-object'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('CacheableTestDomainObject');
|
||||
$this->assertNoCacheTag('foo');
|
||||
$this->drupalGet(Url::fromRoute('early_rendering_controller_test.cacheable-domain-object.early'));
|
||||
$this->assertResponse(500);
|
||||
$this->assertRaw('The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early. Returned object class: Drupal\early_rendering_controller_test\CacheableTestDomainObject.');
|
||||
|
||||
// The exceptions are expected. Do not interpret them as a test failure.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
unlink(\Drupal::root() . '/' . $this->siteDirectory . '/error.log');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Common;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests the format_date() function.
|
||||
*
|
||||
* @group Common
|
||||
*/
|
||||
class FormatDateTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['language'];
|
||||
|
||||
/**
|
||||
* Arbitrary langcode for a custom language.
|
||||
*/
|
||||
const LANGCODE = 'xx';
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp('language');
|
||||
|
||||
$this->config('system.date')
|
||||
->set('timezone.user.configurable', 1)
|
||||
->save();
|
||||
$formats = $this->container->get('entity.manager')
|
||||
->getStorage('date_format')
|
||||
->loadMultiple(['long', 'medium', 'short']);
|
||||
$formats['long']->setPattern('l, j. F Y - G:i')->save();
|
||||
$formats['medium']->setPattern('j. F Y - G:i')->save();
|
||||
$formats['short']->setPattern('Y M j - g:ia')->save();
|
||||
$this->refreshVariables();
|
||||
|
||||
$this->settingsSet('locale_custom_strings_' . self::LANGCODE, [
|
||||
'' => ['Sunday' => 'domingo'],
|
||||
'Long month name' => ['March' => 'marzo'],
|
||||
]);
|
||||
|
||||
ConfigurableLanguage::createFromLangcode(static::LANGCODE)->save();
|
||||
$this->resetAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests admin-defined formats in format_date().
|
||||
*/
|
||||
public function testAdminDefinedFormatDate() {
|
||||
// Create and log in an admin user.
|
||||
$this->drupalLogin($this->drupalCreateUser(['administer site configuration']));
|
||||
|
||||
// Add new date format.
|
||||
$edit = [
|
||||
'id' => 'example_style',
|
||||
'label' => 'Example Style',
|
||||
'date_format_pattern' => 'j M y',
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/date-time/formats/add', $edit, t('Add format'));
|
||||
|
||||
// Add a second date format with a different case than the first.
|
||||
$edit = [
|
||||
'id' => 'example_style_uppercase',
|
||||
'label' => 'Example Style Uppercase',
|
||||
'date_format_pattern' => 'j M Y',
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/date-time/formats/add', $edit, t('Add format'));
|
||||
$this->assertText(t('Custom date format added.'));
|
||||
|
||||
$timestamp = strtotime('2007-03-10T00:00:00+00:00');
|
||||
$this->assertIdentical(format_date($timestamp, 'example_style', '', 'America/Los_Angeles'), '9 Mar 07');
|
||||
$this->assertIdentical(format_date($timestamp, 'example_style_uppercase', '', 'America/Los_Angeles'), '9 Mar 2007');
|
||||
$this->assertIdentical(format_date($timestamp, 'undefined_style'), format_date($timestamp, 'fallback'), 'Test format_date() defaulting to `fallback` when $type not found.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Common;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\node\NodeInterface;
|
||||
|
||||
/**
|
||||
* Tests that anonymous users are not served any JavaScript in the Standard
|
||||
* installation profile.
|
||||
*
|
||||
* @group Common
|
||||
*/
|
||||
class NoJavaScriptAnonymousTest extends WebTestBase {
|
||||
|
||||
protected $profile = 'standard';
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Grant the anonymous user the permission to look at user profiles.
|
||||
user_role_grant_permissions('anonymous', ['access user profiles']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that anonymous users are not served any JavaScript.
|
||||
*/
|
||||
public function testNoJavaScript() {
|
||||
// Create a node that is listed on the frontpage.
|
||||
$this->drupalCreateNode([
|
||||
'promote' => NodeInterface::PROMOTED,
|
||||
]);
|
||||
$user = $this->drupalCreateUser();
|
||||
|
||||
// Test frontpage.
|
||||
$this->drupalGet('');
|
||||
$this->assertNoJavaScriptExceptHtml5Shiv();
|
||||
|
||||
// Test node page.
|
||||
$this->drupalGet('node/1');
|
||||
$this->assertNoJavaScriptExceptHtml5Shiv();
|
||||
|
||||
// Test user profile page.
|
||||
$this->drupalGet('user/' . $user->id());
|
||||
$this->assertNoJavaScriptExceptHtml5Shiv();
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes if no JavaScript is found on the page except the HTML5 shiv.
|
||||
*
|
||||
* The HTML5 shiv is necessary for e.g. the <article> tag which Drupal 8 uses
|
||||
* to work in older browsers like Internet Explorer 8.
|
||||
*/
|
||||
protected function assertNoJavaScriptExceptHtml5Shiv() {
|
||||
// Ensure drupalSettings is not set.
|
||||
$settings = $this->getDrupalSettings();
|
||||
$this->assertTrue(empty($settings), 'drupalSettings is not set.');
|
||||
|
||||
// Ensure the HTML5 shiv exists.
|
||||
$this->assertRaw('html5shiv/html5shiv.min.js', 'HTML5 shiv JavaScript exists.');
|
||||
|
||||
// Ensure no other JavaScript file exists on the page, while ignoring the
|
||||
// HTML5 shiv.
|
||||
$this->assertNoPattern('/(?<!html5shiv\.min)\.js/', "No other JavaScript exists.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Common;
|
||||
|
||||
use Drupal\Component\Serialization\Json;
|
||||
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Performs integration tests on drupal_render().
|
||||
*
|
||||
* @group Common
|
||||
*/
|
||||
class RenderWebTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['common_test'];
|
||||
|
||||
/**
|
||||
* Asserts the cache context for the wrapper format is always present.
|
||||
*/
|
||||
public function testWrapperFormatCacheContext() {
|
||||
$this->drupalGet('common-test/type-link-active-class');
|
||||
$this->assertIdentical(0, strpos($this->getRawContent(), "<!DOCTYPE html>\n<html"));
|
||||
$this->assertIdentical('text/html; charset=UTF-8', $this->drupalGetHeader('Content-Type'));
|
||||
$this->assertTitle('Test active link class | Drupal');
|
||||
$this->assertCacheContext('url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT);
|
||||
|
||||
$this->drupalGet('common-test/type-link-active-class', ['query' => [MainContentViewSubscriber::WRAPPER_FORMAT => 'json']]);
|
||||
$this->assertIdentical('application/json', $this->drupalGetHeader('Content-Type'));
|
||||
$json = Json::decode($this->getRawContent());
|
||||
$this->assertEqual(['content', 'title'], array_keys($json));
|
||||
$this->assertIdentical('Test active link class', $json['title']);
|
||||
$this->assertCacheContext('url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests rendering form elements without passing through
|
||||
* \Drupal::formBuilder()->doBuildForm().
|
||||
*/
|
||||
public function testDrupalRenderFormElements() {
|
||||
// Define a series of form elements.
|
||||
$element = [
|
||||
'#type' => 'button',
|
||||
'#value' => $this->randomMachineName(),
|
||||
];
|
||||
$this->assertRenderedElement($element, '//input[@type=:type]', [':type' => 'submit']);
|
||||
|
||||
$element = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->randomMachineName(),
|
||||
'#value' => $this->randomMachineName(),
|
||||
];
|
||||
$this->assertRenderedElement($element, '//input[@type=:type]', [':type' => 'text']);
|
||||
|
||||
$element = [
|
||||
'#type' => 'password',
|
||||
'#title' => $this->randomMachineName(),
|
||||
];
|
||||
$this->assertRenderedElement($element, '//input[@type=:type]', [':type' => 'password']);
|
||||
|
||||
$element = [
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->randomMachineName(),
|
||||
'#value' => $this->randomMachineName(),
|
||||
];
|
||||
$this->assertRenderedElement($element, '//textarea');
|
||||
|
||||
$element = [
|
||||
'#type' => 'radio',
|
||||
'#title' => $this->randomMachineName(),
|
||||
'#value' => FALSE,
|
||||
];
|
||||
$this->assertRenderedElement($element, '//input[@type=:type]', [':type' => 'radio']);
|
||||
|
||||
$element = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->randomMachineName(),
|
||||
];
|
||||
$this->assertRenderedElement($element, '//input[@type=:type]', [':type' => 'checkbox']);
|
||||
|
||||
$element = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->randomMachineName(),
|
||||
'#options' => [
|
||||
0 => $this->randomMachineName(),
|
||||
1 => $this->randomMachineName(),
|
||||
],
|
||||
];
|
||||
$this->assertRenderedElement($element, '//select');
|
||||
|
||||
$element = [
|
||||
'#type' => 'file',
|
||||
'#title' => $this->randomMachineName(),
|
||||
];
|
||||
$this->assertRenderedElement($element, '//input[@type=:type]', [':type' => 'file']);
|
||||
|
||||
$element = [
|
||||
'#type' => 'item',
|
||||
'#title' => $this->randomMachineName(),
|
||||
'#markup' => $this->randomMachineName(),
|
||||
];
|
||||
$this->assertRenderedElement($element, '//div[contains(@class, :class) and contains(., :markup)]/label[contains(., :label)]', [
|
||||
':class' => 'js-form-type-item',
|
||||
':markup' => $element['#markup'],
|
||||
':label' => $element['#title'],
|
||||
]);
|
||||
|
||||
$element = [
|
||||
'#type' => 'hidden',
|
||||
'#title' => $this->randomMachineName(),
|
||||
'#value' => $this->randomMachineName(),
|
||||
];
|
||||
$this->assertRenderedElement($element, '//input[@type=:type]', [':type' => 'hidden']);
|
||||
|
||||
$element = [
|
||||
'#type' => 'link',
|
||||
'#title' => $this->randomMachineName(),
|
||||
'#url' => Url::fromRoute('common_test.destination'),
|
||||
'#options' => [
|
||||
'absolute' => TRUE,
|
||||
],
|
||||
];
|
||||
$this->assertRenderedElement($element, '//a[@href=:href and contains(., :title)]', [
|
||||
':href' => URL::fromRoute('common_test.destination')->setAbsolute()->toString(),
|
||||
':title' => $element['#title'],
|
||||
]);
|
||||
|
||||
$element = [
|
||||
'#type' => 'details',
|
||||
'#open' => TRUE,
|
||||
'#title' => $this->randomMachineName(),
|
||||
];
|
||||
$this->assertRenderedElement($element, '//details/summary[contains(., :title)]', [
|
||||
':title' => $element['#title'],
|
||||
]);
|
||||
|
||||
$element = [
|
||||
'#type' => 'details',
|
||||
'#open' => TRUE,
|
||||
'#title' => $this->randomMachineName(),
|
||||
];
|
||||
$this->assertRenderedElement($element, '//details');
|
||||
|
||||
$element['item'] = [
|
||||
'#type' => 'item',
|
||||
'#title' => $this->randomMachineName(),
|
||||
'#markup' => $this->randomMachineName(),
|
||||
];
|
||||
$this->assertRenderedElement($element, '//details/div/div[contains(@class, :class) and contains(., :markup)]', [
|
||||
':class' => 'js-form-type-item',
|
||||
':markup' => $element['item']['#markup'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that elements are rendered properly.
|
||||
*/
|
||||
protected function assertRenderedElement(array $element, $xpath, array $xpath_args = []) {
|
||||
$original_element = $element;
|
||||
$this->setRawContent(drupal_render_root($element));
|
||||
$this->verbose('<hr />' . $this->getRawContent());
|
||||
|
||||
// @see \Drupal\simpletest\WebTestBase::xpath()
|
||||
$xpath = $this->buildXPathQuery($xpath, $xpath_args);
|
||||
$element += ['#value' => NULL];
|
||||
$this->assertFieldByXPath($xpath, $element['#value'], format_string('#type @type was properly rendered.', [
|
||||
'@type' => var_export($element['#type'], TRUE),
|
||||
]));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Common;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests SimpleTest error and exception collector.
|
||||
*
|
||||
* @group Common
|
||||
*/
|
||||
class SimpleTestErrorCollectorTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['system_test', 'error_test'];
|
||||
|
||||
/**
|
||||
* Errors triggered during the test.
|
||||
*
|
||||
* Errors are intercepted by the overridden implementation
|
||||
* of Drupal\simpletest\WebTestBase::error() below.
|
||||
*
|
||||
* @var Array
|
||||
*/
|
||||
protected $collectedErrors = [];
|
||||
|
||||
/**
|
||||
* Tests that simpletest collects errors from the tested site.
|
||||
*/
|
||||
public function testErrorCollect() {
|
||||
$this->collectedErrors = [];
|
||||
$this->drupalGet('error-test/generate-warnings-with-report');
|
||||
$this->assertEqual(count($this->collectedErrors), 3, 'Three errors were collected');
|
||||
|
||||
if (count($this->collectedErrors) == 3) {
|
||||
$this->assertError($this->collectedErrors[0], 'Notice', 'Drupal\error_test\Controller\ErrorTestController->generateWarnings()', 'ErrorTestController.php', 'Undefined variable: bananas');
|
||||
$this->assertError($this->collectedErrors[1], 'Warning', 'Drupal\error_test\Controller\ErrorTestController->generateWarnings()', 'ErrorTestController.php', 'Division by zero');
|
||||
$this->assertError($this->collectedErrors[2], 'User warning', 'Drupal\error_test\Controller\ErrorTestController->generateWarnings()', 'ErrorTestController.php', 'Drupal & awesome');
|
||||
}
|
||||
else {
|
||||
// Give back the errors to the log report.
|
||||
foreach ($this->collectedErrors as $error) {
|
||||
parent::error($error['message'], $error['group'], $error['caller']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores errors into an array.
|
||||
*
|
||||
* This test class is trying to verify that simpletest correctly sees errors
|
||||
* and warnings. However, it can't generate errors and warnings that
|
||||
* propagate up to the testing framework itself, or these tests would always
|
||||
* fail. So, this special copy of error() doesn't propagate the errors up
|
||||
* the class hierarchy. It just stuffs them into a protected collectedErrors
|
||||
* array for various assertions to inspect.
|
||||
*/
|
||||
protected function error($message = '', $group = 'Other', array $caller = NULL) {
|
||||
// Due to a WTF elsewhere, simpletest treats debug() and verbose()
|
||||
// messages as if they were an 'error'. But, we don't want to collect
|
||||
// those here. This function just wants to collect the real errors (PHP
|
||||
// notices, PHP fatal errors, etc.), and let all the 'errors' from the
|
||||
// 'User notice' group bubble up to the parent classes to be handled (and
|
||||
// eventually displayed) as normal.
|
||||
if ($group == 'User notice') {
|
||||
parent::error($message, $group, $caller);
|
||||
}
|
||||
// Everything else should be collected but not propagated.
|
||||
else {
|
||||
$this->collectedErrors[] = [
|
||||
'message' => $message,
|
||||
'group' => $group,
|
||||
'caller' => $caller
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a collected error matches what we are expecting.
|
||||
*/
|
||||
public function assertError($error, $group, $function, $file, $message = NULL) {
|
||||
$this->assertEqual($error['group'], $group, format_string("Group was %group", ['%group' => $group]));
|
||||
$this->assertEqual($error['caller']['function'], $function, format_string("Function was %function", ['%function' => $function]));
|
||||
$this->assertEqual(drupal_basename($error['caller']['file']), $file, format_string("File was %file", ['%file' => $file]));
|
||||
if (isset($message)) {
|
||||
$this->assertEqual($error['message'], $message, format_string("Message was %message", ['%message' => $message]));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,320 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Common;
|
||||
|
||||
use Drupal\Component\Utility\UrlHelper;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Confirm that \Drupal\Core\Url,
|
||||
* \Drupal\Component\Utility\UrlHelper::filterQueryParameters(),
|
||||
* \Drupal\Component\Utility\UrlHelper::buildQuery(), and
|
||||
* \Drupal\Core\Utility\LinkGeneratorInterface::generate()
|
||||
* work correctly with various input.
|
||||
*
|
||||
* @group Common
|
||||
*/
|
||||
class UrlTest extends WebTestBase {
|
||||
|
||||
public static $modules = ['common_test', 'url_alter_test'];
|
||||
|
||||
/**
|
||||
* Confirms that invalid URLs are filtered in link generating functions.
|
||||
*/
|
||||
public function testLinkXSS() {
|
||||
// Test \Drupal::l().
|
||||
$text = $this->randomMachineName();
|
||||
$path = "<SCRIPT>alert('XSS')</SCRIPT>";
|
||||
$encoded_path = "3CSCRIPT%3Ealert%28%27XSS%27%29%3C/SCRIPT%3E";
|
||||
|
||||
$link = \Drupal::l($text, Url::fromUserInput('/' . $path));
|
||||
$this->assertTrue(strpos($link, $encoded_path) !== FALSE && strpos($link, $path) === FALSE, format_string('XSS attack @path was filtered by \Drupal\Core\Utility\LinkGeneratorInterface::generate().', ['@path' => $path]));
|
||||
|
||||
// Test \Drupal\Core\Url.
|
||||
$link = Url::fromUri('base:' . $path)->toString();
|
||||
$this->assertTrue(strpos($link, $encoded_path) !== FALSE && strpos($link, $path) === FALSE, format_string('XSS attack @path was filtered by #theme', ['@path' => $path]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that #type=link bubbles outbound route/path processors' metadata.
|
||||
*/
|
||||
public function testLinkBubbleableMetadata() {
|
||||
$cases = [
|
||||
['Regular link', 'internal:/user', [], ['contexts' => [], 'tags' => [], 'max-age' => Cache::PERMANENT], []],
|
||||
['Regular link, absolute', 'internal:/user', ['absolute' => TRUE], ['contexts' => ['url.site'], 'tags' => [], 'max-age' => Cache::PERMANENT], []],
|
||||
['Route processor link', 'route:system.run_cron', [], ['contexts' => ['session'], 'tags' => [], 'max-age' => Cache::PERMANENT], ['placeholders' => []]],
|
||||
['Route processor link, absolute', 'route:system.run_cron', ['absolute' => TRUE], ['contexts' => ['url.site', 'session'], 'tags' => [], 'max-age' => Cache::PERMANENT], ['placeholders' => []]],
|
||||
['Path processor link', 'internal:/user/1', [], ['contexts' => [], 'tags' => ['user:1'], 'max-age' => Cache::PERMANENT], []],
|
||||
['Path processor link, absolute', 'internal:/user/1', ['absolute' => TRUE], ['contexts' => ['url.site'], 'tags' => ['user:1'], 'max-age' => Cache::PERMANENT], []],
|
||||
];
|
||||
|
||||
foreach ($cases as $case) {
|
||||
list($title, $uri, $options, $expected_cacheability, $expected_attachments) = $case;
|
||||
$expected_cacheability['contexts'] = Cache::mergeContexts($expected_cacheability['contexts'], ['languages:language_interface', 'theme', 'user.permissions']);
|
||||
$link = [
|
||||
'#type' => 'link',
|
||||
'#title' => $title,
|
||||
'#options' => $options,
|
||||
'#url' => Url::fromUri($uri),
|
||||
];
|
||||
\Drupal::service('renderer')->renderRoot($link);
|
||||
$this->pass($title);
|
||||
$this->assertEqual($expected_cacheability, $link['#cache']);
|
||||
$this->assertEqual($expected_attachments, $link['#attached']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that default and custom attributes are handled correctly on links.
|
||||
*/
|
||||
public function testLinkAttributes() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
|
||||
// Test that hreflang is added when a link has a known language.
|
||||
$language = new Language(['id' => 'fr', 'name' => 'French']);
|
||||
$hreflang_link = [
|
||||
'#type' => 'link',
|
||||
'#options' => [
|
||||
'language' => $language,
|
||||
],
|
||||
'#url' => Url::fromUri('https://www.drupal.org'),
|
||||
'#title' => 'bar',
|
||||
];
|
||||
$langcode = $language->getId();
|
||||
|
||||
// Test that the default hreflang handling for links does not override a
|
||||
// hreflang attribute explicitly set in the render array.
|
||||
$hreflang_override_link = $hreflang_link;
|
||||
$hreflang_override_link['#options']['attributes']['hreflang'] = 'foo';
|
||||
|
||||
$rendered = $renderer->renderRoot($hreflang_link);
|
||||
$this->assertTrue($this->hasAttribute('hreflang', $rendered, $langcode), format_string('hreflang attribute with value @langcode is present on a rendered link when langcode is provided in the render array.', ['@langcode' => $langcode]));
|
||||
|
||||
$rendered = $renderer->renderRoot($hreflang_override_link);
|
||||
$this->assertTrue($this->hasAttribute('hreflang', $rendered, 'foo'), format_string('hreflang attribute with value @hreflang is present on a rendered link when @hreflang is provided in the render array.', ['@hreflang' => 'foo']));
|
||||
|
||||
// Test the active class in links produced by
|
||||
// \Drupal\Core\Utility\LinkGeneratorInterface::generate() and #type 'link'.
|
||||
$options_no_query = [];
|
||||
$options_query = [
|
||||
'query' => [
|
||||
'foo' => 'bar',
|
||||
'one' => 'two',
|
||||
],
|
||||
];
|
||||
$options_query_reverse = [
|
||||
'query' => [
|
||||
'one' => 'two',
|
||||
'foo' => 'bar',
|
||||
],
|
||||
];
|
||||
|
||||
// Test #type link.
|
||||
$path = 'common-test/type-link-active-class';
|
||||
|
||||
$this->drupalGet($path, $options_no_query);
|
||||
$links = $this->xpath('//a[@href = :href and contains(@class, :class)]', [':href' => Url::fromRoute('common_test.l_active_class', [], $options_no_query)->toString(), ':class' => 'is-active']);
|
||||
$this->assertTrue(isset($links[0]), 'A link generated by the link generator to the current page is marked active.');
|
||||
|
||||
$links = $this->xpath('//a[@href = :href and not(contains(@class, :class))]', [':href' => Url::fromRoute('common_test.l_active_class', [], $options_query)->toString(), ':class' => 'is-active']);
|
||||
$this->assertTrue(isset($links[0]), 'A link generated by the link generator to the current page with a query string when the current page has no query string is not marked active.');
|
||||
|
||||
$this->drupalGet($path, $options_query);
|
||||
$links = $this->xpath('//a[@href = :href and contains(@class, :class)]', [':href' => Url::fromRoute('common_test.l_active_class', [], $options_query)->toString(), ':class' => 'is-active']);
|
||||
$this->assertTrue(isset($links[0]), 'A link generated by the link generator to the current page with a query string that matches the current query string is marked active.');
|
||||
|
||||
$links = $this->xpath('//a[@href = :href and contains(@class, :class)]', [':href' => Url::fromRoute('common_test.l_active_class', [], $options_query_reverse)->toString(), ':class' => 'is-active']);
|
||||
$this->assertTrue(isset($links[0]), 'A link generated by the link generator to the current page with a query string that has matching parameters to the current query string but in a different order is marked active.');
|
||||
|
||||
$links = $this->xpath('//a[@href = :href and not(contains(@class, :class))]', [':href' => Url::fromRoute('common_test.l_active_class', [], $options_no_query)->toString(), ':class' => 'is-active']);
|
||||
$this->assertTrue(isset($links[0]), 'A link generated by the link generator to the current page without a query string when the current page has a query string is not marked active.');
|
||||
|
||||
// Test adding a custom class in links produced by
|
||||
// \Drupal\Core\Utility\LinkGeneratorInterface::generate() and #type 'link'.
|
||||
// Test the link generator.
|
||||
$class_l = $this->randomMachineName();
|
||||
$link_l = \Drupal::l($this->randomMachineName(), new Url('<current>', [], ['attributes' => ['class' => [$class_l]]]));
|
||||
$this->assertTrue($this->hasAttribute('class', $link_l, $class_l), format_string('Custom class @class is present on link when requested by l()', ['@class' => $class_l]));
|
||||
|
||||
// Test #type.
|
||||
$class_theme = $this->randomMachineName();
|
||||
$type_link = [
|
||||
'#type' => 'link',
|
||||
'#title' => $this->randomMachineName(),
|
||||
'#url' => Url::fromRoute('<current>'),
|
||||
'#options' => [
|
||||
'attributes' => [
|
||||
'class' => [$class_theme],
|
||||
],
|
||||
],
|
||||
];
|
||||
$link_theme = $renderer->renderRoot($type_link);
|
||||
$this->assertTrue($this->hasAttribute('class', $link_theme, $class_theme), format_string('Custom class @class is present on link when requested by #type', ['@class' => $class_theme]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that link functions support render arrays as 'text'.
|
||||
*/
|
||||
public function testLinkRenderArrayText() {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
|
||||
// Build a link with the link generator for reference.
|
||||
$l = \Drupal::l('foo', Url::fromUri('https://www.drupal.org'));
|
||||
|
||||
// Test a renderable array passed to the link generator.
|
||||
$renderer->executeInRenderContext(new RenderContext(), function () use ($renderer, $l) {
|
||||
$renderable_text = ['#markup' => 'foo'];
|
||||
$l_renderable_text = \Drupal::l($renderable_text, Url::fromUri('https://www.drupal.org'));
|
||||
$this->assertEqual($l_renderable_text, $l);
|
||||
});
|
||||
|
||||
// Test a themed link with plain text 'text'.
|
||||
$type_link_plain_array = [
|
||||
'#type' => 'link',
|
||||
'#title' => 'foo',
|
||||
'#url' => Url::fromUri('https://www.drupal.org'),
|
||||
];
|
||||
$type_link_plain = $renderer->renderRoot($type_link_plain_array);
|
||||
$this->assertEqual($type_link_plain, $l);
|
||||
|
||||
// Build a themed link with renderable 'text'.
|
||||
$type_link_nested_array = [
|
||||
'#type' => 'link',
|
||||
'#title' => ['#markup' => 'foo'],
|
||||
'#url' => Url::fromUri('https://www.drupal.org'),
|
||||
];
|
||||
$type_link_nested = $renderer->renderRoot($type_link_nested_array);
|
||||
$this->assertEqual($type_link_nested, $l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for class existence in link.
|
||||
*
|
||||
* @param $link
|
||||
* URL to search.
|
||||
* @param $class
|
||||
* Element class to search for.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the class is found, FALSE otherwise.
|
||||
*/
|
||||
private function hasAttribute($attribute, $link, $class) {
|
||||
return preg_match('|' . $attribute . '="([^\"\s]+\s+)*' . $class . '|', $link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests UrlHelper::filterQueryParameters().
|
||||
*/
|
||||
public function testDrupalGetQueryParameters() {
|
||||
$original = [
|
||||
'a' => 1,
|
||||
'b' => [
|
||||
'd' => 4,
|
||||
'e' => [
|
||||
'f' => 5,
|
||||
],
|
||||
],
|
||||
'c' => 3,
|
||||
];
|
||||
|
||||
// First-level exclusion.
|
||||
$result = $original;
|
||||
unset($result['b']);
|
||||
$this->assertEqual(UrlHelper::filterQueryParameters($original, ['b']), $result, "'b' was removed.");
|
||||
|
||||
// Second-level exclusion.
|
||||
$result = $original;
|
||||
unset($result['b']['d']);
|
||||
$this->assertEqual(UrlHelper::filterQueryParameters($original, ['b[d]']), $result, "'b[d]' was removed.");
|
||||
|
||||
// Third-level exclusion.
|
||||
$result = $original;
|
||||
unset($result['b']['e']['f']);
|
||||
$this->assertEqual(UrlHelper::filterQueryParameters($original, ['b[e][f]']), $result, "'b[e][f]' was removed.");
|
||||
|
||||
// Multiple exclusions.
|
||||
$result = $original;
|
||||
unset($result['a'], $result['b']['e'], $result['c']);
|
||||
$this->assertEqual(UrlHelper::filterQueryParameters($original, ['a', 'b[e]', 'c']), $result, "'a', 'b[e]', 'c' were removed.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests UrlHelper::parse().
|
||||
*/
|
||||
public function testDrupalParseUrl() {
|
||||
// Relative, absolute, and external URLs, without/with explicit script path,
|
||||
// without/with Drupal path.
|
||||
foreach (['', '/', 'https://www.drupal.org/'] as $absolute) {
|
||||
foreach (['', 'index.php/'] as $script) {
|
||||
foreach (['', 'foo/bar'] as $path) {
|
||||
$url = $absolute . $script . $path . '?foo=bar&bar=baz&baz#foo';
|
||||
$expected = [
|
||||
'path' => $absolute . $script . $path,
|
||||
'query' => ['foo' => 'bar', 'bar' => 'baz', 'baz' => ''],
|
||||
'fragment' => 'foo',
|
||||
];
|
||||
$this->assertEqual(UrlHelper::parse($url), $expected, 'URL parsed correctly.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Relative URL that is known to confuse parse_url().
|
||||
$url = 'foo/bar:1';
|
||||
$result = [
|
||||
'path' => 'foo/bar:1',
|
||||
'query' => [],
|
||||
'fragment' => '',
|
||||
];
|
||||
$this->assertEqual(UrlHelper::parse($url), $result, 'Relative URL parsed correctly.');
|
||||
|
||||
// Test that drupal can recognize an absolute URL. Used to prevent attack vectors.
|
||||
$url = 'https://www.drupal.org/foo/bar?foo=bar&bar=baz&baz#foo';
|
||||
$this->assertTrue(UrlHelper::isExternal($url), 'Correctly identified an external URL.');
|
||||
|
||||
// Test that UrlHelper::parse() does not allow spoofing a URL to force a malicious redirect.
|
||||
$parts = UrlHelper::parse('forged:http://cwe.mitre.org/data/definitions/601.html');
|
||||
$this->assertFalse(UrlHelper::isValid($parts['path'], TRUE), '\Drupal\Component\Utility\UrlHelper::isValid() correctly parsed a forged URL.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests external URL handling.
|
||||
*/
|
||||
public function testExternalUrls() {
|
||||
$test_url = 'https://www.drupal.org/';
|
||||
|
||||
// Verify external URL can contain a fragment.
|
||||
$url = $test_url . '#drupal';
|
||||
$result = Url::fromUri($url)->toString();
|
||||
$this->assertEqual($url, $result, 'External URL with fragment works without a fragment in $options.');
|
||||
|
||||
// Verify fragment can be overridden in an external URL.
|
||||
$url = $test_url . '#drupal';
|
||||
$fragment = $this->randomMachineName(10);
|
||||
$result = Url::fromUri($url, ['fragment' => $fragment])->toString();
|
||||
$this->assertEqual($test_url . '#' . $fragment, $result, 'External URL fragment is overridden with a custom fragment in $options.');
|
||||
|
||||
// Verify external URL can contain a query string.
|
||||
$url = $test_url . '?drupal=awesome';
|
||||
$result = Url::fromUri($url)->toString();
|
||||
$this->assertEqual($url, $result);
|
||||
|
||||
// Verify external URL can be extended with a query string.
|
||||
$url = $test_url;
|
||||
$query = [$this->randomMachineName(5) => $this->randomMachineName(5)];
|
||||
$result = Url::fromUri($url, ['query' => $query])->toString();
|
||||
$this->assertEqual($url . '?' . http_build_query($query, '', '&'), $result, 'External URL can be extended with a query string in $options.');
|
||||
|
||||
// Verify query string can be extended in an external URL.
|
||||
$url = $test_url . '?drupal=awesome';
|
||||
$query = [$this->randomMachineName(5) => $this->randomMachineName(5)];
|
||||
$result = Url::fromUri($url, ['query' => $query])->toString();
|
||||
$this->assertEqual($url . '&' . http_build_query($query, '', '&'), $result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,11 +14,15 @@ use Drupal\system\Tests\Cache\PageCacheTagsTestBase;
|
||||
use Drupal\user\Entity\Role;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
@trigger_error(__NAMESPACE__ . '\EntityCacheTagsTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use \Drupal\Tests\system\Functional\Entity\EntityCacheTagsTestBase. See https://www.drupal.org/node/2946549.', E_USER_DEPRECATED);
|
||||
|
||||
/**
|
||||
* Provides helper methods for Entity cache tags tests.
|
||||
*
|
||||
* @deprecated Scheduled for removal in Drupal 9.0.0.
|
||||
* Use \Drupal\Tests\system\Functional\Entity\EntityCacheTagsTestBase instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2946549
|
||||
*/
|
||||
abstract class EntityCacheTagsTestBase extends PageCacheTagsTestBase {
|
||||
|
||||
|
||||
@@ -5,8 +5,15 @@ namespace Drupal\system\Tests\Entity;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\entity_test\FieldStorageDefinition;
|
||||
|
||||
@trigger_error(__NAMESPACE__ . '\EntityDefinitionTestTrait is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use \Drupal\Tests\system\Functional\Entity\Traits\EntityDefinitionTestTrait. See https://www.drupal.org/node/2946549.', E_USER_DEPRECATED);
|
||||
|
||||
/**
|
||||
* Provides some test methods used to update existing entity definitions.
|
||||
*
|
||||
* @deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0.
|
||||
* Use \Drupal\Tests\system\Functional\Entity\Traits\EntityDefinitionTestTrait.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2946549
|
||||
*/
|
||||
trait EntityDefinitionTestTrait {
|
||||
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Entity;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests the entity form.
|
||||
*
|
||||
* @group Entity
|
||||
*/
|
||||
class EntityFormTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['entity_test', 'language'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$web_user = $this->drupalCreateUser(['administer entity_test content', 'view test entity']);
|
||||
$this->drupalLogin($web_user);
|
||||
|
||||
// Add a language.
|
||||
ConfigurableLanguage::createFromLangcode('ro')->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests basic form CRUD functionality.
|
||||
*/
|
||||
public function testFormCRUD() {
|
||||
// All entity variations have to have the same results.
|
||||
foreach (entity_test_entity_types() as $entity_type) {
|
||||
$this->doTestFormCRUD($entity_type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests basic multilingual form CRUD functionality.
|
||||
*/
|
||||
public function testMultilingualFormCRUD() {
|
||||
// All entity variations have to have the same results.
|
||||
foreach (entity_test_entity_types(ENTITY_TEST_TYPES_MULTILINGUAL) as $entity_type) {
|
||||
$this->doTestMultilingualFormCRUD($entity_type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hook_entity_form_display_alter().
|
||||
*
|
||||
* @see entity_test_entity_form_display_alter()
|
||||
*/
|
||||
public function testEntityFormDisplayAlter() {
|
||||
$this->drupalGet('entity_test/add');
|
||||
$altered_field = $this->xpath('//input[@name="field_test_text[0][value]" and @size="42"]');
|
||||
$this->assertTrue(count($altered_field) === 1, 'The altered field has the correct size value.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the form CRUD tests for the given entity type.
|
||||
*
|
||||
* @param string $entity_type
|
||||
* The entity type to run the tests with.
|
||||
*/
|
||||
protected function doTestFormCRUD($entity_type) {
|
||||
$name1 = $this->randomMachineName(8);
|
||||
$name2 = $this->randomMachineName(10);
|
||||
|
||||
$edit = [
|
||||
'name[0][value]' => $name1,
|
||||
'field_test_text[0][value]' => $this->randomMachineName(16),
|
||||
];
|
||||
|
||||
$this->drupalPostForm($entity_type . '/add', $edit, t('Save'));
|
||||
$entity = $this->loadEntityByName($entity_type, $name1);
|
||||
$this->assertTrue($entity, format_string('%entity_type: Entity found in the database.', ['%entity_type' => $entity_type]));
|
||||
|
||||
$edit['name[0][value]'] = $name2;
|
||||
$this->drupalPostForm($entity_type . '/manage/' . $entity->id() . '/edit', $edit, t('Save'));
|
||||
$entity = $this->loadEntityByName($entity_type, $name1);
|
||||
$this->assertFalse($entity, format_string('%entity_type: The entity has been modified.', ['%entity_type' => $entity_type]));
|
||||
$entity = $this->loadEntityByName($entity_type, $name2);
|
||||
$this->assertTrue($entity, format_string('%entity_type: Modified entity found in the database.', ['%entity_type' => $entity_type]));
|
||||
$this->assertNotEqual($entity->name->value, $name1, format_string('%entity_type: The entity name has been modified.', ['%entity_type' => $entity_type]));
|
||||
|
||||
$this->drupalGet($entity_type . '/manage/' . $entity->id() . '/edit');
|
||||
$this->clickLink(t('Delete'));
|
||||
$this->drupalPostForm(NULL, [], t('Delete'));
|
||||
$entity = $this->loadEntityByName($entity_type, $name2);
|
||||
$this->assertFalse($entity, format_string('%entity_type: Entity not found in the database.', ['%entity_type' => $entity_type]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the multilingual form CRUD tests for the given entity type ID.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The ID of entity type to run the tests with.
|
||||
*/
|
||||
protected function doTestMultilingualFormCRUD($entity_type_id) {
|
||||
$name1 = $this->randomMachineName(8);
|
||||
$name1_ro = $this->randomMachineName(9);
|
||||
$name2_ro = $this->randomMachineName(11);
|
||||
|
||||
$edit = [
|
||||
'name[0][value]' => $name1,
|
||||
'field_test_text[0][value]' => $this->randomMachineName(16),
|
||||
];
|
||||
|
||||
$this->drupalPostForm($entity_type_id . '/add', $edit, t('Save'));
|
||||
$entity = $this->loadEntityByName($entity_type_id, $name1);
|
||||
$this->assertTrue($entity, format_string('%entity_type: Entity found in the database.', ['%entity_type' => $entity_type_id]));
|
||||
|
||||
// Add a translation to the newly created entity without using the Content
|
||||
// translation module.
|
||||
$entity->addTranslation('ro', ['name' => $name1_ro])->save();
|
||||
$translated_entity = $this->loadEntityByName($entity_type_id, $name1)->getTranslation('ro');
|
||||
$this->assertEqual($translated_entity->name->value, $name1_ro, format_string('%entity_type: The translation has been added.', ['%entity_type' => $entity_type_id]));
|
||||
|
||||
$edit['name[0][value]'] = $name2_ro;
|
||||
$this->drupalPostForm('ro/' . $entity_type_id . '/manage/' . $entity->id() . '/edit', $edit, t('Save'));
|
||||
$translated_entity = $this->loadEntityByName($entity_type_id, $name1)->getTranslation('ro');
|
||||
$this->assertTrue($translated_entity, format_string('%entity_type: Modified translation found in the database.', ['%entity_type' => $entity_type_id]));
|
||||
$this->assertEqual($translated_entity->name->value, $name2_ro, format_string('%entity_type: The name of the translation has been modified.', ['%entity_type' => $entity_type_id]));
|
||||
|
||||
$this->drupalGet('ro/' . $entity_type_id . '/manage/' . $entity->id() . '/edit');
|
||||
$this->clickLink(t('Delete'));
|
||||
$this->drupalPostForm(NULL, [], t('Delete Romanian translation'));
|
||||
$entity = $this->loadEntityByName($entity_type_id, $name1);
|
||||
$this->assertNotNull($entity, format_string('%entity_type: The original entity still exists.', ['%entity_type' => $entity_type_id]));
|
||||
$this->assertFalse($entity->hasTranslation('ro'), format_string('%entity_type: Entity translation does not exist anymore.', ['%entity_type' => $entity_type_id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a test entity by name always resetting the storage cache.
|
||||
*/
|
||||
protected function loadEntityByName($entity_type, $name) {
|
||||
// Always load the entity from the database to ensure that changes are
|
||||
// correctly picked up.
|
||||
$entity_storage = $this->container->get('entity.manager')->getStorage($entity_type);
|
||||
$entity_storage->resetCache();
|
||||
$entities = $entity_storage->loadByProperties(['name' => $name]);
|
||||
return $entities ? current($entities) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that validation handlers works as expected.
|
||||
*/
|
||||
public function testValidationHandlers() {
|
||||
/** @var \Drupal\Core\State\StateInterface $state */
|
||||
$state = $this->container->get('state');
|
||||
|
||||
// Check that from-level validation handlers can be defined and can alter
|
||||
// the form array.
|
||||
$state->set('entity_test.form.validate.test', 'form-level');
|
||||
$this->drupalPostForm('entity_test/add', [], 'Save');
|
||||
$this->assertTrue($state->get('entity_test.form.validate.result'), 'Form-level validation handlers behave correctly.');
|
||||
|
||||
// Check that defining a button-level validation handler causes an exception
|
||||
// to be thrown.
|
||||
$state->set('entity_test.form.validate.test', 'button-level');
|
||||
$this->drupalPostForm('entity_test/add', [], 'Save');
|
||||
$this->assertEqual($state->get('entity_test.form.save.exception'), 'Drupal\Core\Entity\EntityStorageException: Entity validation was skipped.', 'Button-level validation handlers behave correctly.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Entity;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests entity translation form.
|
||||
*
|
||||
* @group Entity
|
||||
*/
|
||||
class EntityTranslationFormTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['entity_test', 'language', 'node'];
|
||||
|
||||
protected $langcodes;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
// Enable translations for the test entity type.
|
||||
\Drupal::state()->set('entity_test.translation', TRUE);
|
||||
|
||||
// Create test languages.
|
||||
$this->langcodes = [];
|
||||
for ($i = 0; $i < 2; ++$i) {
|
||||
$language = ConfigurableLanguage::create([
|
||||
'id' => 'l' . $i,
|
||||
'label' => $this->randomString(),
|
||||
]);
|
||||
$this->langcodes[$i] = $language->id();
|
||||
$language->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests entity form language.
|
||||
*/
|
||||
public function testEntityFormLanguage() {
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
|
||||
|
||||
$web_user = $this->drupalCreateUser(['create page content', 'edit own page content', 'administer content types']);
|
||||
$this->drupalLogin($web_user);
|
||||
|
||||
// Create a node with language LanguageInterface::LANGCODE_NOT_SPECIFIED.
|
||||
$edit = [];
|
||||
$edit['title[0][value]'] = $this->randomMachineName(8);
|
||||
$edit['body[0][value]'] = $this->randomMachineName(16);
|
||||
$this->drupalGet('node/add/page');
|
||||
$form_langcode = \Drupal::state()->get('entity_test.form_langcode');
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
|
||||
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
|
||||
|
||||
$this->assertTrue($node->language()->getId() == $form_langcode, 'Form language is the same as the entity language.');
|
||||
|
||||
// Edit the node and test the form language.
|
||||
$this->drupalGet($this->langcodes[0] . '/node/' . $node->id() . '/edit');
|
||||
$form_langcode = \Drupal::state()->get('entity_test.form_langcode');
|
||||
$this->assertTrue($node->language()->getId() == $form_langcode, 'Form language is the same as the entity language.');
|
||||
|
||||
// Explicitly set form langcode.
|
||||
$langcode = $this->langcodes[0];
|
||||
$form_state_additions['langcode'] = $langcode;
|
||||
\Drupal::service('entity.form_builder')->getForm($node, 'default', $form_state_additions);
|
||||
$form_langcode = \Drupal::state()->get('entity_test.form_langcode');
|
||||
$this->assertTrue($langcode == $form_langcode, 'Form language is the same as the language parameter.');
|
||||
|
||||
// Enable language selector.
|
||||
$this->drupalGet('admin/structure/types/manage/page');
|
||||
$edit = ['language_configuration[language_alterable]' => TRUE, 'language_configuration[langcode]' => LanguageInterface::LANGCODE_NOT_SPECIFIED];
|
||||
$this->drupalPostForm('admin/structure/types/manage/page', $edit, t('Save content type'));
|
||||
$this->assertRaw(t('The content type %type has been updated.', ['%type' => 'Basic page']), 'Basic page content type has been updated.');
|
||||
|
||||
// Create a node with language.
|
||||
$edit = [];
|
||||
$langcode = $this->langcodes[0];
|
||||
$edit['title[0][value]'] = $this->randomMachineName(8);
|
||||
$edit['body[0][value]'] = $this->randomMachineName(16);
|
||||
$edit['langcode[0][value]'] = $langcode;
|
||||
$this->drupalPostForm('node/add/page', $edit, t('Save'));
|
||||
$this->assertText(t('Basic page @title has been created.', ['@title' => $edit['title[0][value]']]), 'Basic page created.');
|
||||
|
||||
// Verify that the creation message contains a link to a node.
|
||||
$view_link = $this->xpath('//div[@class="messages"]//a[contains(@href, :href)]', [':href' => 'node/']);
|
||||
$this->assert(isset($view_link), 'The message area contains a link to a node');
|
||||
|
||||
// Check to make sure the node was created.
|
||||
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
|
||||
$this->assertTrue($node, 'Node found in database.');
|
||||
|
||||
// Make body translatable.
|
||||
$field_storage = FieldStorageConfig::loadByName('node', 'body');
|
||||
$field_storage->setTranslatable(TRUE);
|
||||
$field_storage->save();
|
||||
$field_storage = FieldStorageConfig::loadByName('node', 'body');
|
||||
$this->assertTrue($field_storage->isTranslatable(), 'Field body is translatable.');
|
||||
|
||||
// Create a body translation and check the form language.
|
||||
$langcode2 = $this->langcodes[1];
|
||||
$translation = $node->addTranslation($langcode2);
|
||||
$translation->title->value = $this->randomString();
|
||||
$translation->body->value = $this->randomMachineName(16);
|
||||
$translation->setOwnerId($web_user->id());
|
||||
$node->save();
|
||||
$this->drupalGet($langcode2 . '/node/' . $node->id() . '/edit');
|
||||
$form_langcode = \Drupal::state()->get('entity_test.form_langcode');
|
||||
$this->assertTrue($langcode2 == $form_langcode, "Node edit form language is $langcode2.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Drupal\system\Tests\Entity;
|
||||
|
||||
@trigger_error(__FILE__ . ' is deprecated in Drupal 8.1.0 and will be removed before Drupal 9.0.0. Use \Drupal\KernelTests\Core\Entity\EntityKernelTestBase instead.', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\simpletest\KernelTestBase;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\user\Entity\Role;
|
||||
@@ -10,7 +12,7 @@ use Drupal\user\Entity\User;
|
||||
/**
|
||||
* Defines an abstract test base for entity unit tests.
|
||||
*
|
||||
* @deprecated in Drupal 8.1.x, will be removed before Drupal 8.2.x. Use
|
||||
* @deprecated in Drupal 8.1.0, will be removed before Drupal 9.0.0. Use
|
||||
* \Drupal\KernelTests\Core\Entity\EntityKernelTestBase instead.
|
||||
*/
|
||||
abstract class EntityUnitTestBase extends KernelTestBase {
|
||||
|
||||
@@ -7,8 +7,15 @@ use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
|
||||
@trigger_error(__NAMESPACE__ . '\EntityWithUriCacheTagsTestBase is deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Instead, use \Drupal\Tests\system\Functional\Entity\EntityWithUriCacheTagsTestBase. See https://www.drupal.org/node/2946549.', E_USER_DEPRECATED);
|
||||
|
||||
/**
|
||||
* Provides helper methods for Entity cache tags tests; for entities with URIs.
|
||||
*
|
||||
* @deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0.
|
||||
* Use \Drupal\Tests\system\Functional\Entity\EntityWithUriCacheTagsTestBase.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2946549
|
||||
*/
|
||||
abstract class EntityWithUriCacheTagsTestBase extends EntityCacheTagsTestBase {
|
||||
|
||||
|
||||
@@ -163,7 +163,6 @@ class ElementsTableSelectTest extends WebTestBase {
|
||||
$this->assertNoFieldByXPath('//th[@class="select-all"]', NULL, 'Do not display a "Select all" checkbox when #multiple is FALSE, even when #js_select is TRUE.');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test the whether the option checker gives an error on invalid tableselect values for checkboxes.
|
||||
*/
|
||||
@@ -187,7 +186,6 @@ class ElementsTableSelectTest extends WebTestBase {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test the whether the option checker gives an error on invalid tableselect values for radios.
|
||||
*/
|
||||
@@ -211,7 +209,6 @@ class ElementsTableSelectTest extends WebTestBase {
|
||||
$this->assertTrue(isset($errors['tableselect']), 'Option checker disallows invalid values for radio buttons.');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for the option check test to submit a form while collecting errors.
|
||||
*
|
||||
@@ -248,7 +245,7 @@ class ElementsTableSelectTest extends WebTestBase {
|
||||
$errors = $form_state->getErrors();
|
||||
|
||||
// Clear errors and messages.
|
||||
drupal_get_messages();
|
||||
\Drupal::messenger()->deleteAll();
|
||||
$form_state->clearErrors();
|
||||
|
||||
// Return the processed form together with form_state and errors
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Drupal\system\Tests\Image;
|
||||
@trigger_error(__FILE__ . ' is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Use Drupal\FunctionalTests\Image\ToolkitTestBase instead. See https://www.drupal.org/node/2862641.', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
|
||||
/**
|
||||
* Base class for image manipulation testing.
|
||||
@@ -106,10 +106,10 @@ abstract class ToolkitTestBase extends WebTestBase {
|
||||
// Determine if there were any expected that were not called.
|
||||
$uncalled = array_diff($expected, $actual);
|
||||
if (count($uncalled)) {
|
||||
$this->assertTrue(FALSE, SafeMarkup::format('Expected operations %expected to be called but %uncalled was not called.', ['%expected' => implode(', ', $expected), '%uncalled' => implode(', ', $uncalled)]));
|
||||
$this->assertTrue(FALSE, new FormattableMarkup('Expected operations %expected to be called but %uncalled was not called.', ['%expected' => implode(', ', $expected), '%uncalled' => implode(', ', $uncalled)]));
|
||||
}
|
||||
else {
|
||||
$this->assertTrue(TRUE, SafeMarkup::format('All the expected operations were called: %expected', ['%expected' => implode(', ', $expected)]));
|
||||
$this->assertTrue(TRUE, new FormattableMarkup('All the expected operations were called: %expected', ['%expected' => implode(', ', $expected)]));
|
||||
}
|
||||
|
||||
// Determine if there were any unexpected calls.
|
||||
@@ -117,7 +117,7 @@ abstract class ToolkitTestBase extends WebTestBase {
|
||||
// count it as an error.
|
||||
$unexpected = array_diff($actual, $expected);
|
||||
if (count($unexpected) && (!in_array('apply', $expected) || count(array_intersect($unexpected, $operations)) !== count($unexpected))) {
|
||||
$this->assertTrue(FALSE, SafeMarkup::format('Unexpected operations were called: %unexpected.', ['%unexpected' => implode(', ', $unexpected)]));
|
||||
$this->assertTrue(FALSE, new FormattableMarkup('Unexpected operations were called: %unexpected.', ['%unexpected' => implode(', ', $unexpected)]));
|
||||
}
|
||||
else {
|
||||
$this->assertTrue(TRUE, 'No unexpected operations were called.');
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
@trigger_error(__NAMESPACE__ . '\ConfigAfterInstallerTestBase is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Instead, use \Drupal\FunctionalTests\Installer\ConfigAfterInstallerTestBase.', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\Core\Config\FileStorage;
|
||||
use Drupal\Core\Config\InstallStorage;
|
||||
use Drupal\Core\Config\StorageInterface;
|
||||
@@ -10,6 +12,9 @@ use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Provides a class for install profiles to check their installed config.
|
||||
*
|
||||
* @deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0.
|
||||
* Use \Drupal\FunctionalTests\Installer\ConfigAfterInstallerTestBase.
|
||||
*/
|
||||
abstract class ConfigAfterInstallerTestBase extends InstallerTestBase {
|
||||
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Component\Serialization\Yaml;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Tests distribution profile support with existing settings.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class DistributionProfileExistingSettingsTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* The distribution profile info.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $info;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->info = [
|
||||
'type' => 'profile',
|
||||
'core' => \Drupal::CORE_COMPATIBILITY,
|
||||
'name' => 'Distribution profile',
|
||||
'distribution' => [
|
||||
'name' => 'My Distribution',
|
||||
'install' => [
|
||||
'theme' => 'bartik',
|
||||
],
|
||||
],
|
||||
];
|
||||
// File API functions are not available yet.
|
||||
$path = $this->siteDirectory . '/profiles/mydistro';
|
||||
mkdir($path, 0777, TRUE);
|
||||
file_put_contents("$path/mydistro.info.yml", Yaml::encode($this->info));
|
||||
|
||||
// Pre-configure hash salt.
|
||||
// Any string is valid, so simply use the class name of this test.
|
||||
$this->settings['settings']['hash_salt'] = (object) [
|
||||
'value' => __CLASS__,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure database credentials.
|
||||
$connection_info = Database::getConnectionInfo();
|
||||
unset($connection_info['default']['pdo']);
|
||||
unset($connection_info['default']['init_commands']);
|
||||
|
||||
$this->settings['databases']['default'] = (object) [
|
||||
'value' => $connection_info,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Use the kernel to find the site path because the site.path service should
|
||||
// not be available at this point in the install process.
|
||||
$site_path = DrupalKernel::findSitePath(Request::createFromGlobals());
|
||||
// Pre-configure config directories.
|
||||
$this->settings['config_directories'] = [
|
||||
CONFIG_SYNC_DIRECTORY => (object) [
|
||||
'value' => $site_path . '/files/config_staging',
|
||||
'required' => TRUE,
|
||||
],
|
||||
];
|
||||
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Make settings file not writable.
|
||||
$filename = $this->siteDirectory . '/settings.php';
|
||||
// Make the settings file read-only.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
chmod($filename, 0444);
|
||||
|
||||
// Verify that the distribution name appears.
|
||||
$this->assertRaw($this->info['distribution']['name']);
|
||||
// Verify that the requested theme is used.
|
||||
$this->assertRaw($this->info['distribution']['install']['theme']);
|
||||
// Verify that the "Choose profile" step does not appear.
|
||||
$this->assertNoText('profile');
|
||||
|
||||
parent::setUpLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is a distribution profile.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// This step should not appear, since settings.php is fully configured
|
||||
// already.
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->rootUser->getUsername());
|
||||
|
||||
// Confirm that Drupal recognizes this distribution as the current profile.
|
||||
$this->assertEqual(\Drupal::installProfile(), 'mydistro');
|
||||
$this->assertNull(Settings::get('install_profile'), 'The install profile has not been written to settings.php.');
|
||||
$this->assertEqual($this->config('core.extension')->get('profile'), 'mydistro', 'The install profile has been written to core.extension configuration.');
|
||||
|
||||
$this->rebuildContainer();
|
||||
$this->pass('Container can be rebuilt even though distribution is not written to settings.php.');
|
||||
$this->assertEqual(\Drupal::installProfile(), 'mydistro');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Tests distribution profile support.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class DistributionProfileTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* The distribution profile info.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $info;
|
||||
|
||||
protected function setUp() {
|
||||
$this->info = [
|
||||
'type' => 'profile',
|
||||
'core' => \Drupal::CORE_COMPATIBILITY,
|
||||
'name' => 'Distribution profile',
|
||||
'distribution' => [
|
||||
'name' => 'My Distribution',
|
||||
'install' => [
|
||||
'theme' => 'bartik',
|
||||
],
|
||||
],
|
||||
];
|
||||
// File API functions are not available yet.
|
||||
$path = $this->siteDirectory . '/profiles/mydistro';
|
||||
mkdir($path, 0777, TRUE);
|
||||
file_put_contents("$path/mydistro.info.yml", Yaml::encode($this->info));
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Verify that the distribution name appears.
|
||||
$this->assertRaw($this->info['distribution']['name']);
|
||||
// Verify that the distribution name is used in the site title.
|
||||
$this->assertTitle('Choose language | ' . $this->info['distribution']['name']);
|
||||
// Verify that the requested theme is used.
|
||||
$this->assertRaw($this->info['distribution']['install']['theme']);
|
||||
// Verify that the "Choose profile" step does not appear.
|
||||
$this->assertNoText('profile');
|
||||
|
||||
parent::setUpLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is a distribution profile.
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->rootUser->getUsername());
|
||||
|
||||
// Confirm that Drupal recognizes this distribution as the current profile.
|
||||
$this->assertEqual(\Drupal::installProfile(), 'mydistro');
|
||||
$this->assertEqual(Settings::get('install_profile'), 'mydistro', 'The install profile has been written to settings.php.');
|
||||
$this->assertEqual($this->config('core.extension')->get('profile'), 'mydistro', 'The install profile has been written to core.extension configuration.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Tests distribution profile support with a 'langcode' query string.
|
||||
*
|
||||
* @group Installer
|
||||
*
|
||||
* @see \Drupal\system\Tests\Installer\DistributionProfileTranslationTest
|
||||
*/
|
||||
class DistributionProfileTranslationQueryTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $langcode = 'de';
|
||||
|
||||
/**
|
||||
* The distribution profile info.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $info;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->info = [
|
||||
'type' => 'profile',
|
||||
'core' => \Drupal::CORE_COMPATIBILITY,
|
||||
'name' => 'Distribution profile',
|
||||
'distribution' => [
|
||||
'name' => 'My Distribution',
|
||||
'langcode' => $this->langcode,
|
||||
'install' => [
|
||||
'theme' => 'bartik',
|
||||
],
|
||||
],
|
||||
];
|
||||
// File API functions are not available yet.
|
||||
$path = $this->siteDirectory . '/profiles/mydistro';
|
||||
mkdir($path, 0777, TRUE);
|
||||
file_put_contents("$path/mydistro.info.yml", Yaml::encode($this->info));
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function visitInstaller() {
|
||||
// Place a custom local translation in the translations directory.
|
||||
mkdir(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
|
||||
file_put_contents(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
|
||||
file_put_contents(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.fr.po', $this->getPo('fr'));
|
||||
|
||||
// Pass a different language code than the one set in the distribution
|
||||
// profile. This distribution language should still be used.
|
||||
// The unrouted URL assembler does not exist at this point, so we build the
|
||||
// URL ourselves.
|
||||
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php' . '?langcode=fr');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// This step is skipped, because the distribution profile uses a fixed
|
||||
// language.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is a distribution profile.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// The language should have been automatically detected, all following
|
||||
// screens should be translated already.
|
||||
$elements = $this->xpath('//input[@type="submit"]/@value');
|
||||
$this->assertEqual((string) current($elements), 'Save and continue de');
|
||||
$this->translations['Save and continue'] = 'Save and continue de';
|
||||
|
||||
// Check the language direction.
|
||||
$direction = (string) current($this->xpath('/html/@dir'));
|
||||
$this->assertEqual($direction, 'ltr');
|
||||
|
||||
// Verify that the distribution name appears.
|
||||
$this->assertRaw($this->info['distribution']['name']);
|
||||
// Verify that the requested theme is used.
|
||||
$this->assertRaw($this->info['distribution']['install']['theme']);
|
||||
// Verify that the "Choose profile" step does not appear.
|
||||
$this->assertNoText('profile');
|
||||
|
||||
parent::setUpSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->rootUser->getDisplayName());
|
||||
|
||||
// Verify German was configured but not English.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->assertText('German');
|
||||
$this->assertNoText('English');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string for the test .po file.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The language code.
|
||||
* @return string
|
||||
* Contents for the test .po file.
|
||||
*/
|
||||
protected function getPo($langcode) {
|
||||
return <<<ENDPO
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
msgid "Save and continue"
|
||||
msgstr "Save and continue $langcode"
|
||||
ENDPO;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Tests distribution profile support.
|
||||
*
|
||||
* @group Installer
|
||||
*
|
||||
* @see \Drupal\system\Tests\Installer\DistributionProfileTest
|
||||
*/
|
||||
class DistributionProfileTranslationTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $langcode = 'de';
|
||||
|
||||
/**
|
||||
* The distribution profile info.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $info;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->info = [
|
||||
'type' => 'profile',
|
||||
'core' => \Drupal::CORE_COMPATIBILITY,
|
||||
'name' => 'Distribution profile',
|
||||
'distribution' => [
|
||||
'name' => 'My Distribution',
|
||||
'langcode' => $this->langcode,
|
||||
'install' => [
|
||||
'theme' => 'bartik',
|
||||
],
|
||||
],
|
||||
];
|
||||
// File API functions are not available yet.
|
||||
$path = $this->siteDirectory . '/profiles/mydistro';
|
||||
mkdir($path, 0777, TRUE);
|
||||
file_put_contents("$path/mydistro.info.yml", Yaml::encode($this->info));
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function visitInstaller() {
|
||||
// Place a custom local translation in the translations directory.
|
||||
mkdir(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
|
||||
file_put_contents(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
|
||||
|
||||
parent::visitInstaller();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// This step is skipped, because the distribution profile uses a fixed
|
||||
// language.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is a distribution profile.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// The language should have been automatically detected, all following
|
||||
// screens should be translated already.
|
||||
$elements = $this->xpath('//input[@type="submit"]/@value');
|
||||
$this->assertEqual((string) current($elements), 'Save and continue de');
|
||||
$this->translations['Save and continue'] = 'Save and continue de';
|
||||
|
||||
// Check the language direction.
|
||||
$direction = (string) current($this->xpath('/html/@dir'));
|
||||
$this->assertEqual($direction, 'ltr');
|
||||
|
||||
// Verify that the distribution name appears.
|
||||
$this->assertRaw($this->info['distribution']['name']);
|
||||
// Verify that the requested theme is used.
|
||||
$this->assertRaw($this->info['distribution']['install']['theme']);
|
||||
// Verify that the "Choose profile" step does not appear.
|
||||
$this->assertNoText('profile');
|
||||
|
||||
parent::setUpSettings();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->rootUser->getDisplayName());
|
||||
|
||||
// Verify German was configured but not English.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->assertText('German');
|
||||
$this->assertNoText('English');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string for the test .po file.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The language code.
|
||||
* @return string
|
||||
* Contents for the test .po file.
|
||||
*/
|
||||
protected function getPo($langcode) {
|
||||
return <<<ENDPO
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
msgid "Save and continue"
|
||||
msgstr "Save and continue $langcode"
|
||||
ENDPO;
|
||||
}
|
||||
|
||||
}
|
||||
-62
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Component\Utility\Crypt;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Tests the installer when a config_directory set up but does not exist.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerConfigDirectorySetNoDirectoryErrorTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* The directory where the sync directory should be created during install.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $configDirectory;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->configDirectory = $this->publicFilesDirectory . '/config_' . Crypt::randomBytesBase64();
|
||||
$this->settings['config_directories'][CONFIG_SYNC_DIRECTORY] = (object) [
|
||||
'value' => $this->configDirectory . '/sync',
|
||||
'required' => TRUE,
|
||||
];
|
||||
// Create the files directory early so we can test the error case.
|
||||
mkdir($this->publicFilesDirectory);
|
||||
// Create a file so the directory can not be created.
|
||||
file_put_contents($this->configDirectory, 'Test');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Configure settings.
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// This step should not appear as we had a failure prior to the settings
|
||||
// screen.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
// This step should not appear as we had a failure prior to the settings
|
||||
// screen.
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation failed.
|
||||
*/
|
||||
public function testError() {
|
||||
$this->assertText("An automated attempt to create the directory {$this->configDirectory}/sync failed, possibly due to a permissions problem.");
|
||||
$this->assertFalse(file_exists($this->configDirectory . '/sync') && is_dir($this->configDirectory . '/sync'), "The directory {$this->configDirectory}/sync does not exist.");
|
||||
}
|
||||
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Component\Utility\Crypt;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Tests the installer when a config_directory set up but does not exist.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerConfigDirectorySetNoDirectoryTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* The sync directory created during the install.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $syncDirectory;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->syncDirectory = $this->publicFilesDirectory . '/config_' . Crypt::randomBytesBase64() . '/sync';
|
||||
$this->settings['config_directories'][CONFIG_SYNC_DIRECTORY] = (object) [
|
||||
'value' => $this->syncDirectory,
|
||||
'required' => TRUE,
|
||||
];
|
||||
// Other directories will be created too.
|
||||
$this->settings['config_directories']['custom'] = (object) [
|
||||
'value' => $this->publicFilesDirectory . '/config_custom',
|
||||
'required' => TRUE,
|
||||
];
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
$this->assertTrue(file_exists($this->syncDirectory) && is_dir($this->syncDirectory), "The directory {$this->syncDirectory} exists.");
|
||||
$this->assertTrue(file_exists($this->publicFilesDirectory . '/config_custom') && is_dir($this->publicFilesDirectory . '/config_custom'), "The directory {$this->publicFilesDirectory}/custom_config exists.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Tests the installer with database errors.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerDatabaseErrorMessagesTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// We are creating a table here to force an error in the installer because
|
||||
// it will try and create the drupal_install_test table as this is part of
|
||||
// the standard database tests performed by the installer in
|
||||
// Drupal\Core\Database\Install\Tasks.
|
||||
Database::getConnection('default')->query('CREATE TABLE {drupal_install_test} (id int NULL)');
|
||||
parent::setUpSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
// This step should not appear as we had a failure on the settings screen.
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the error message in the settings step is correct.
|
||||
*/
|
||||
public function testSetUpSettingsErrorMessage() {
|
||||
$this->assertRaw('<ul><li>Failed to <strong>CREATE</strong> a test table');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Tests the installer with empty settings file.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerEmptySettingsTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
// Create an empty settings.php file.
|
||||
touch($this->siteDirectory . '/settings.php');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Tests the installer when a config_directory has already been set up.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingConfigDirectoryTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* The expected file perms of the folder.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $expectedFilePerms;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
mkdir($this->siteDirectory . '/config_read_only', 0444);
|
||||
$this->expectedFilePerms = fileperms($this->siteDirectory . '/config_read_only');
|
||||
$this->settings['config_directories'][CONFIG_SYNC_DIRECTORY] = (object) [
|
||||
'value' => $this->siteDirectory . '/config_read_only',
|
||||
'required' => TRUE,
|
||||
];
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
$this->assertEqual($this->expectedFilePerms, fileperms($this->siteDirectory . '/config_read_only'));
|
||||
$this->assertEqual([], glob($this->siteDirectory . '/config_read_only/*'), 'The sync directory is empty after install because it is read-only.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
use Drupal\Core\Database\Database;
|
||||
|
||||
/**
|
||||
* Tests the installer with an existing settings file with database connection
|
||||
* info.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingDatabaseSettingsTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
// Pre-configure database credentials in settings.php.
|
||||
$connection_info = Database::getConnectionInfo();
|
||||
unset($connection_info['default']['pdo']);
|
||||
unset($connection_info['default']['init_commands']);
|
||||
|
||||
$this->settings['databases']['default'] = (object) [
|
||||
'value' => $connection_info,
|
||||
'required' => TRUE,
|
||||
];
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @todo The database settings form is not supposed to appear if settings.php
|
||||
* contains a valid database connection already (but e.g. no config
|
||||
* directories yet).
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// All database settings should be pre-configured, except password.
|
||||
$values = $this->parameters['forms']['install_settings_form'];
|
||||
$driver = $values['driver'];
|
||||
$edit = [];
|
||||
if (isset($values[$driver]['password']) && $values[$driver]['password'] !== '') {
|
||||
$edit = $this->translatePostValues([
|
||||
$driver => [
|
||||
'password' => $values[$driver]['password'],
|
||||
],
|
||||
]);
|
||||
}
|
||||
$this->drupalPostForm(NULL, $edit, $this->translations['Save and continue']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Tests the installer with an existing Drupal installation.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingInstallationTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that Drupal can't be reinstalled while an existing installation is
|
||||
* available.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
// Verify that Drupal can't be immediately reinstalled.
|
||||
$this->visitInstaller();
|
||||
$this->assertRaw('Drupal already installed');
|
||||
|
||||
// Delete settings.php and attempt to reinstall again.
|
||||
unlink($this->siteDirectory . '/settings.php');
|
||||
$this->visitInstaller();
|
||||
$this->setUpLanguage();
|
||||
$this->setUpProfile();
|
||||
$this->setUpRequirementsProblem();
|
||||
$this->setUpSettings();
|
||||
$this->assertRaw('Drupal already installed');
|
||||
}
|
||||
|
||||
}
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Tests installer breaks with a profile mismatch and a read-only settings.php.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingSettingsMismatchProfileBrokenTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Configures a preexisting settings.php file without an install_profile
|
||||
* setting before invoking the interactive installer.
|
||||
*/
|
||||
protected function setUp() {
|
||||
// Pre-configure hash salt.
|
||||
// Any string is valid, so simply use the class name of this test.
|
||||
$this->settings['settings']['hash_salt'] = (object) [
|
||||
'value' => __CLASS__,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure database credentials.
|
||||
$connection_info = Database::getConnectionInfo();
|
||||
unset($connection_info['default']['pdo']);
|
||||
unset($connection_info['default']['init_commands']);
|
||||
|
||||
$this->settings['databases']['default'] = (object) [
|
||||
'value' => $connection_info,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// During interactive install we'll change this to a different profile and
|
||||
// this test will ensure that the new value is written to settings.php.
|
||||
$this->settings['settings']['install_profile'] = (object) [
|
||||
'value' => 'minimal',
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure config directories.
|
||||
$site_path = DrupalKernel::findSitePath(Request::createFromGlobals());
|
||||
$this->settings['config_directories'] = [
|
||||
CONFIG_SYNC_DIRECTORY => (object) [
|
||||
'value' => $site_path . '/files/config_staging',
|
||||
'required' => TRUE,
|
||||
],
|
||||
];
|
||||
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function visitInstaller() {
|
||||
// Make settings file not writable. This will break the installer.
|
||||
$filename = $this->siteDirectory . '/settings.php';
|
||||
// Make the settings file read-only.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
chmod($filename, 0444);
|
||||
|
||||
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php?langcode=en&profile=testing');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// This step is skipped, because there is a lagcode as a query param.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is a profile as a query param.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// This step should not appear, since settings.php is fully configured
|
||||
// already.
|
||||
}
|
||||
|
||||
protected function setUpSite() {
|
||||
// This step should not appear, since settings.php could not be written.
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation did not succeed.
|
||||
*/
|
||||
public function testBrokenInstaller() {
|
||||
$this->assertTitle('Install profile mismatch | Drupal');
|
||||
$this->assertText("The selected profile testing does not match the install_profile setting, which is minimal. Cannot write updated setting to {$this->siteDirectory}/settings.php.");
|
||||
}
|
||||
|
||||
}
|
||||
-101
@@ -1,101 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Tests the installer with an existing settings file but no install profile.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingSettingsMismatchProfileTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Configures a preexisting settings.php file without an install_profile
|
||||
* setting before invoking the interactive installer.
|
||||
*/
|
||||
protected function setUp() {
|
||||
// Pre-configure hash salt.
|
||||
// Any string is valid, so simply use the class name of this test.
|
||||
$this->settings['settings']['hash_salt'] = (object) [
|
||||
'value' => __CLASS__,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure database credentials.
|
||||
$connection_info = Database::getConnectionInfo();
|
||||
unset($connection_info['default']['pdo']);
|
||||
unset($connection_info['default']['init_commands']);
|
||||
|
||||
$this->settings['databases']['default'] = (object) [
|
||||
'value' => $connection_info,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// During interactive install we'll change this to a different profile and
|
||||
// this test will ensure that the new value is written to settings.php.
|
||||
$this->settings['settings']['install_profile'] = (object) [
|
||||
'value' => 'minimal',
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure config directories.
|
||||
$this->settings['config_directories'] = [
|
||||
CONFIG_SYNC_DIRECTORY => (object) [
|
||||
'value' => DrupalKernel::findSitePath(Request::createFromGlobals()) . '/files/config_sync',
|
||||
'required' => TRUE,
|
||||
],
|
||||
];
|
||||
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function visitInstaller() {
|
||||
// Provide profile and language in query string to skip these pages.
|
||||
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php?langcode=en&profile=testing');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// This step is skipped, because there is a lagcode as a query param.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is a profile as a query param.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// This step should not appear, since settings.php is fully configured
|
||||
// already.
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
$this->assertEqual('testing', \Drupal::installProfile());
|
||||
$this->assertEqual('testing', Settings::get('install_profile'), 'Profile was correctly changed to testing in Settings.php');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Tests the installer with an existing settings file but no install profile.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingSettingsNoProfileTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Configures a preexisting settings.php file without an install_profile
|
||||
* setting before invoking the interactive installer.
|
||||
*/
|
||||
protected function setUp() {
|
||||
// Pre-configure hash salt.
|
||||
// Any string is valid, so simply use the class name of this test.
|
||||
$this->settings['settings']['hash_salt'] = (object) [
|
||||
'value' => __CLASS__,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure database credentials.
|
||||
$connection_info = Database::getConnectionInfo();
|
||||
unset($connection_info['default']['pdo']);
|
||||
unset($connection_info['default']['init_commands']);
|
||||
|
||||
$this->settings['databases']['default'] = (object) [
|
||||
'value' => $connection_info,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure config directories.
|
||||
$this->settings['config_directories'] = [
|
||||
CONFIG_SYNC_DIRECTORY => (object) [
|
||||
'value' => DrupalKernel::findSitePath(Request::createFromGlobals()) . '/files/config_sync',
|
||||
'required' => TRUE,
|
||||
],
|
||||
];
|
||||
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// This step should not appear, since settings.php is fully configured
|
||||
// already.
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
$this->assertEqual('testing', \Drupal::installProfile());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\DrupalKernel;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Tests the installer with an existing settings file.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerExistingSettingsTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Fully configures a preexisting settings.php file before invoking the
|
||||
* interactive installer.
|
||||
*/
|
||||
protected function setUp() {
|
||||
// Pre-configure hash salt.
|
||||
// Any string is valid, so simply use the class name of this test.
|
||||
$this->settings['settings']['hash_salt'] = (object) [
|
||||
'value' => __CLASS__,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// During interactive install we'll change this to a different profile and
|
||||
// this test will ensure that the new value is written to settings.php.
|
||||
$this->settings['settings']['install_profile'] = (object) [
|
||||
'value' => 'minimal',
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Pre-configure database credentials.
|
||||
$connection_info = Database::getConnectionInfo();
|
||||
unset($connection_info['default']['pdo']);
|
||||
unset($connection_info['default']['init_commands']);
|
||||
|
||||
$this->settings['databases']['default'] = (object) [
|
||||
'value' => $connection_info,
|
||||
'required' => TRUE,
|
||||
];
|
||||
|
||||
// Use the kernel to find the site path because the site.path service should
|
||||
// not be available at this point in the install process.
|
||||
$site_path = DrupalKernel::findSitePath(Request::createFromGlobals());
|
||||
// Pre-configure config directories.
|
||||
$this->settings['config_directories'] = [
|
||||
CONFIG_SYNC_DIRECTORY => (object) [
|
||||
'value' => $site_path . '/files/config_sync',
|
||||
'required' => TRUE,
|
||||
],
|
||||
];
|
||||
mkdir($this->settings['config_directories'][CONFIG_SYNC_DIRECTORY]->value, 0777, TRUE);
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// This step should not appear, since settings.php is fully configured
|
||||
// already.
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that installation succeeded.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
$this->assertEqual('testing', \Drupal::installProfile(), 'Profile was changed from minimal to testing during interactive install.');
|
||||
$this->assertEqual('testing', Settings::get('install_profile'), 'Profile was correctly changed to testing in Settings.php');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Verifies that the early installer uses the correct language direction.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerLanguageDirectionTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* Overrides the language code the installer should use.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $langcode = 'ar';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Place a custom local translation in the translations directory.
|
||||
mkdir(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
|
||||
file_put_contents(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.ar.po', "msgid \"\"\nmsgstr \"\"\nmsgid \"Save and continue\"\nmsgstr \"Save and continue Arabic\"");
|
||||
|
||||
parent::setUpLanguage();
|
||||
// After selecting a different language than English, all following screens
|
||||
// should be translated already.
|
||||
$elements = $this->xpath('//input[@type="submit"]/@value');
|
||||
$this->assertEqual((string) current($elements), 'Save and continue Arabic');
|
||||
$this->translations['Save and continue'] = 'Save and continue Arabic';
|
||||
|
||||
// Verify that language direction is right-to-left.
|
||||
$direction = (string) current($this->xpath('/html/@dir'));
|
||||
$this->assertEqual($direction, 'rtl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Core\Language\LanguageManager;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Verifies that the installer language list combines local and remote languages.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerLanguagePageTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* Installer step: Select language.
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Place a custom local translation in the translations directory.
|
||||
mkdir(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
|
||||
touch(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.xoxo.po');
|
||||
|
||||
// Check that all predefined languages show up with their native names.
|
||||
$this->visitInstaller();
|
||||
foreach (LanguageManager::getStandardLanguageList() as $langcode => $names) {
|
||||
$this->assertOption('edit-langcode', $langcode);
|
||||
$this->assertRaw('>' . $names[1] . '<');
|
||||
}
|
||||
|
||||
// Check that our custom one shows up with the file name indicated language.
|
||||
$this->assertOption('edit-langcode', 'xoxo');
|
||||
$this->assertRaw('>xoxo<');
|
||||
|
||||
parent::setUpLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Tests the interactive installer.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* Ensures that the user page is available after installation.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->rootUser->getUsername());
|
||||
|
||||
// Verify that the confirmation message appears.
|
||||
require_once \Drupal::root() . '/core/includes/install.inc';
|
||||
$this->assertRaw(t('Congratulations, you installed @drupal!', [
|
||||
'@drupal' => drupal_install_profile_distribution_name(),
|
||||
]));
|
||||
|
||||
// Ensure that the timezone is correct for sites under test after installing
|
||||
// interactively.
|
||||
$this->assertEqual($this->config('system.date')->get('timezone.default'), 'Australia/Sydney');
|
||||
}
|
||||
|
||||
/**
|
||||
* Installer step: Select language.
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Test that \Drupal\Core\Render\BareHtmlPageRenderer adds assets and
|
||||
// metatags as expected to the first page of the installer.
|
||||
$this->assertRaw('core/themes/seven/css/components/buttons.css');
|
||||
$this->assertRaw('<meta charset="utf-8" />');
|
||||
|
||||
// Assert that the expected title is present.
|
||||
$this->assertEqual('Choose language', $this->cssSelect('main h2')[0]);
|
||||
|
||||
parent::setUpLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// Assert that the expected title is present.
|
||||
$this->assertEqual('Select an installation profile', $this->cssSelect('main h2')[0]);
|
||||
$result = $this->xpath('//span[contains(@class, :class) and contains(text(), :text)]', [':class' => 'visually-hidden', ':text' => 'Select an installation profile']);
|
||||
$this->assertEqual(count($result), 1, "Title/Label not displayed when '#title_display' => 'invisible' attribute is set");
|
||||
|
||||
parent::setUpProfile();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// Assert that the expected title is present.
|
||||
$this->assertEqual('Database configuration', $this->cssSelect('main h2')[0]);
|
||||
|
||||
parent::setUpSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
// Assert that the expected title is present.
|
||||
$this->assertEqual('Configure site', $this->cssSelect('main h2')[0]);
|
||||
|
||||
parent::setUpSite();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function visitInstaller() {
|
||||
parent::visitInstaller();
|
||||
|
||||
// Assert the title is correct and has the title suffix.
|
||||
$this->assertTitle('Choose language | Drupal');
|
||||
}
|
||||
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
/**
|
||||
* Tests translation files for multiple languages get imported during install.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerTranslationMultipleLanguageForeignTest extends InstallerTranslationMultipleLanguageTest {
|
||||
|
||||
/**
|
||||
* Overrides the language code in which to install Drupal.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $langcode = 'de';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
parent::setUpLanguage();
|
||||
$this->translations['Save and continue'] = 'Save and continue de';
|
||||
}
|
||||
|
||||
}
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
/**
|
||||
* Tests that keeping English in a foreign language install works.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerTranslationMultipleLanguageKeepEnglishTest extends InstallerTranslationMultipleLanguageForeignTest {
|
||||
|
||||
/**
|
||||
* Switch to the multilingual testing profile with English kept.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $profile = 'testing_multilingual_with_english';
|
||||
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Tests translation files for multiple languages get imported during install.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerTranslationMultipleLanguageTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* Switch to the multilingual testing profile.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $profile = 'testing_multilingual';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Place custom local translations in the translations directory.
|
||||
mkdir(DRUPAL_ROOT . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
|
||||
file_put_contents(DRUPAL_ROOT . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
|
||||
file_put_contents(DRUPAL_ROOT . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.es.po', $this->getPo('es'));
|
||||
|
||||
parent::setUpLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string for the test .po file.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The language code.
|
||||
* @return string
|
||||
* Contents for the test .po file.
|
||||
*/
|
||||
protected function getPo($langcode) {
|
||||
return <<<ENDPO
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
msgid "Save and continue"
|
||||
msgstr "Save and continue $langcode"
|
||||
|
||||
msgid "Anonymous"
|
||||
msgstr "Anonymous $langcode"
|
||||
|
||||
msgid "Language"
|
||||
msgstr "Language $langcode"
|
||||
|
||||
#: Testing site name configuration during the installer.
|
||||
msgid "Drupal"
|
||||
msgstr "Drupal"
|
||||
ENDPO;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function installParameters() {
|
||||
$params = parent::installParameters();
|
||||
$params['forms']['install_configure_form']['site_name'] = 'SITE_NAME_' . $this->langcode;
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that translations ended up at the expected places.
|
||||
*/
|
||||
public function testTranslationsLoaded() {
|
||||
// Ensure the title is correct.
|
||||
$this->assertEqual('SITE_NAME_' . $this->langcode, \Drupal::config('system.site')->get('name'));
|
||||
|
||||
// Verify German and Spanish were configured.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->assertText('German');
|
||||
$this->assertText('Spanish');
|
||||
// If the installer was English or we used a profile that keeps English, we
|
||||
// expect that configured also. Otherwise English should not be configured
|
||||
// on the site.
|
||||
if ($this->langcode == 'en' || $this->profile == 'testing_multilingual_with_english') {
|
||||
$this->assertText('English');
|
||||
}
|
||||
else {
|
||||
$this->assertNoText('English');
|
||||
}
|
||||
|
||||
// Verify the strings from the translation files were imported.
|
||||
$this->verifyImportedStringsTranslated();
|
||||
|
||||
/** @var \Drupal\language\ConfigurableLanguageManager $language_manager */
|
||||
$language_manager = \Drupal::languageManager();
|
||||
|
||||
// If the site was installed in a foreign language (only tested with German
|
||||
// in subclasses), then the active configuration should be updated and no
|
||||
// override should exist in German. Otherwise the German translation should
|
||||
// end up in overrides the same way as Spanish (which is not used as a site
|
||||
// installation language). English should be available based on profile
|
||||
// information and should be possible to add if not yet added, making
|
||||
// English overrides available.
|
||||
|
||||
$config = \Drupal::config('user.settings');
|
||||
$override_de = $language_manager->getLanguageConfigOverride('de', 'user.settings');
|
||||
$override_en = $language_manager->getLanguageConfigOverride('en', 'user.settings');
|
||||
$override_es = $language_manager->getLanguageConfigOverride('es', 'user.settings');
|
||||
|
||||
if ($this->langcode == 'de') {
|
||||
// Active configuration should be in German and no German override should
|
||||
// exist.
|
||||
$this->assertEqual($config->get('anonymous'), 'Anonymous de');
|
||||
$this->assertEqual($config->get('langcode'), 'de');
|
||||
$this->assertTrue($override_de->isNew());
|
||||
|
||||
if ($this->profile == 'testing_multilingual_with_english') {
|
||||
// English is already added in this profile. Should make the override
|
||||
// available.
|
||||
$this->assertEqual($override_en->get('anonymous'), 'Anonymous');
|
||||
}
|
||||
else {
|
||||
// English is not yet available.
|
||||
$this->assertTrue($override_en->isNew());
|
||||
|
||||
// Adding English should make the English override available.
|
||||
$edit = ['predefined_langcode' => 'en'];
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
$override_en = $language_manager->getLanguageConfigOverride('en', 'user.settings');
|
||||
$this->assertEqual($override_en->get('anonymous'), 'Anonymous');
|
||||
}
|
||||
|
||||
// Activate a module, to make sure that config is not overridden by module
|
||||
// installation.
|
||||
$edit = [
|
||||
'modules[views][enable]' => TRUE,
|
||||
'modules[filter][enable]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm('admin/modules', $edit, t('Install'));
|
||||
|
||||
// Verify the strings from the translation are still as expected.
|
||||
$this->verifyImportedStringsTranslated();
|
||||
}
|
||||
else {
|
||||
// Active configuration should be English.
|
||||
$this->assertEqual($config->get('anonymous'), 'Anonymous');
|
||||
$this->assertEqual($config->get('langcode'), 'en');
|
||||
// There should not be an English override.
|
||||
$this->assertTrue($override_en->isNew());
|
||||
// German should be an override.
|
||||
$this->assertEqual($override_de->get('anonymous'), 'Anonymous de');
|
||||
}
|
||||
|
||||
// Spanish is always an override (never used as installation language).
|
||||
$this->assertEqual($override_es->get('anonymous'), 'Anonymous es');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to verify that the expected strings are translated.
|
||||
*/
|
||||
protected function verifyImportedStringsTranslated() {
|
||||
$test_samples = ['Save and continue', 'Anonymous', 'Language'];
|
||||
$langcodes = ['de', 'es'];
|
||||
|
||||
foreach ($test_samples as $sample) {
|
||||
foreach ($langcodes as $langcode) {
|
||||
$edit = [];
|
||||
$edit['langcode'] = $langcode;
|
||||
$edit['translation'] = 'translated';
|
||||
$edit['string'] = $sample;
|
||||
$this->drupalPostForm('admin/config/regional/translate', $edit, t('Filter'));
|
||||
$this->assertText($sample . ' ' . $langcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Installs Drupal in German and checks resulting site.
|
||||
*
|
||||
* @group Installer
|
||||
*
|
||||
* @see \Drupal\system\Tests\Installer\InstallerTranslationTest
|
||||
*/
|
||||
class InstallerTranslationQueryTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* Overrides the language code in which to install Drupal.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $langcode = 'de';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function visitInstaller() {
|
||||
// Place a custom local translation in the translations directory.
|
||||
mkdir(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
|
||||
file_put_contents(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
|
||||
|
||||
// The unrouted URL assembler does not exist at this point, so we build the
|
||||
// URL ourselves.
|
||||
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php' . '?langcode=' . $this->langcode);
|
||||
|
||||
// The language should have been automatically detected, all following
|
||||
// screens should be translated already.
|
||||
$elements = $this->xpath('//input[@type="submit"]/@value');
|
||||
$this->assertEqual((string) current($elements), 'Save and continue de');
|
||||
$this->translations['Save and continue'] = 'Save and continue de';
|
||||
|
||||
// Check the language direction.
|
||||
$direction = (string) current($this->xpath('/html/@dir'));
|
||||
$this->assertEqual($direction, 'ltr');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// The language was was preset by passing a query parameter in the URL, so
|
||||
// no explicit language selection is necessary.
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the expected behaviors of the installation result.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Verify German was configured but not English.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->assertText('German');
|
||||
$this->assertNoText('English');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string for the test .po file.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The language code.
|
||||
* @return string
|
||||
* Contents for the test .po file.
|
||||
*/
|
||||
protected function getPo($langcode) {
|
||||
return <<<ENDPO
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
msgid "Save and continue"
|
||||
msgstr "Save and continue $langcode"
|
||||
ENDPO;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Installs Drupal in German and checks resulting site.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class InstallerTranslationTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* Overrides the language code in which to install Drupal.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $langcode = 'de';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Place a custom local translation in the translations directory.
|
||||
mkdir(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations', 0777, TRUE);
|
||||
file_put_contents(\Drupal::root() . '/' . $this->siteDirectory . '/files/translations/drupal-8.0.0.de.po', $this->getPo('de'));
|
||||
|
||||
parent::setUpLanguage();
|
||||
|
||||
// After selecting a different language than English, all following screens
|
||||
// should be translated already.
|
||||
$elements = $this->xpath('//input[@type="submit"]/@value');
|
||||
$this->assertEqual((string) current($elements), 'Save and continue de');
|
||||
$this->translations['Save and continue'] = 'Save and continue de';
|
||||
|
||||
// Check the language direction.
|
||||
$direction = (string) current($this->xpath('/html/@dir'));
|
||||
$this->assertEqual($direction, 'ltr');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSettings() {
|
||||
// We are creating a table here to force an error in the installer because
|
||||
// it will try and create the drupal_install_test table as this is part of
|
||||
// the standard database tests performed by the installer in
|
||||
// Drupal\Core\Database\Install\Tasks.
|
||||
Database::getConnection('default')->query('CREATE TABLE {drupal_install_test} (id int NULL)');
|
||||
parent::setUpSettings();
|
||||
|
||||
// Ensure that the error message translation is working.
|
||||
$this->assertRaw('Beheben Sie alle Probleme unten, um die Installation fortzusetzen. Informationen zur Konfiguration der Datenbankserver finden Sie in der <a href="https://www.drupal.org/getting-started/install">Installationshandbuch</a>, oder kontaktieren Sie Ihren Hosting-Anbieter.');
|
||||
$this->assertRaw('<strong>CREATE</strong> ein Test-Tabelle auf Ihrem Datenbankserver mit dem Befehl <em class="placeholder">CREATE TABLE {drupal_install_test} (id int NULL)</em> fehlgeschlagen.');
|
||||
|
||||
// Now do it successfully.
|
||||
Database::getConnection('default')->query('DROP TABLE {drupal_install_test}');
|
||||
parent::setUpSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the expected behaviors of the installation result.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Verify German was configured but not English.
|
||||
$this->drupalGet('admin/config/regional/language');
|
||||
$this->assertText('German');
|
||||
$this->assertNoText('English');
|
||||
|
||||
// The current container still has the english as current language, rebuild.
|
||||
$this->rebuildContainer();
|
||||
/** @var \Drupal\user\Entity\User $account */
|
||||
$account = User::load(0);
|
||||
$this->assertEqual($account->language()->getId(), 'en', 'Anonymous user is English.');
|
||||
$account = User::load(1);
|
||||
$this->assertEqual($account->language()->getId(), 'en', 'Administrator user is English.');
|
||||
$account = $this->drupalCreateUser();
|
||||
$this->assertEqual($account->language()->getId(), 'de', 'New user is German.');
|
||||
|
||||
// Ensure that we can enable basic_auth on a non-english site.
|
||||
$this->drupalPostForm('admin/modules', ['modules[basic_auth][enable]' => TRUE], t('Install'));
|
||||
$this->assertResponse(200);
|
||||
|
||||
// Assert that the theme CSS was added to the page.
|
||||
$edit = ['preprocess_css' => FALSE];
|
||||
$this->drupalPostForm('admin/config/development/performance', $edit, t('Save configuration'));
|
||||
$this->drupalGet('<front>');
|
||||
$this->assertRaw('classy/css/components/action-links.css');
|
||||
|
||||
// Verify the strings from the translation files were imported.
|
||||
$test_samples = ['Save and continue', 'Anonymous'];
|
||||
foreach ($test_samples as $sample) {
|
||||
$edit = [];
|
||||
$edit['langcode'] = 'de';
|
||||
$edit['translation'] = 'translated';
|
||||
$edit['string'] = $sample;
|
||||
$this->drupalPostForm('admin/config/regional/translate', $edit, t('Filter'));
|
||||
$this->assertText($sample . ' de');
|
||||
}
|
||||
|
||||
/** @var \Drupal\language\ConfigurableLanguageManager $language_manager */
|
||||
$language_manager = \Drupal::languageManager();
|
||||
|
||||
// Installed in German, configuration should be in German. No German or
|
||||
// English overrides should be present.
|
||||
$config = \Drupal::config('user.settings');
|
||||
$override_de = $language_manager->getLanguageConfigOverride('de', 'user.settings');
|
||||
$override_en = $language_manager->getLanguageConfigOverride('en', 'user.settings');
|
||||
$this->assertEqual($config->get('anonymous'), 'Anonymous de');
|
||||
$this->assertEqual($config->get('langcode'), 'de');
|
||||
$this->assertTrue($override_de->isNew());
|
||||
$this->assertTrue($override_en->isNew());
|
||||
|
||||
// Assert that adding English makes the English override available.
|
||||
$edit = ['predefined_langcode' => 'en'];
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
$override_en = $language_manager->getLanguageConfigOverride('en', 'user.settings');
|
||||
$this->assertFalse($override_en->isNew());
|
||||
$this->assertEqual($override_en->get('anonymous'), 'Anonymous');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string for the test .po file.
|
||||
*
|
||||
* @param string $langcode
|
||||
* The language code.
|
||||
* @return string
|
||||
* Contents for the test .po file.
|
||||
*/
|
||||
protected function getPo($langcode) {
|
||||
return <<<ENDPO
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
msgid "Save and continue"
|
||||
msgstr "Save and continue $langcode"
|
||||
|
||||
msgid "Anonymous"
|
||||
msgstr "Anonymous $langcode"
|
||||
|
||||
msgid "Resolve all issues below to continue the installation. For help configuring your database server, see the <a href="https://www.drupal.org/getting-started/install">installation handbook</a>, or contact your hosting provider."
|
||||
msgstr "Beheben Sie alle Probleme unten, um die Installation fortzusetzen. Informationen zur Konfiguration der Datenbankserver finden Sie in der <a href="https://www.drupal.org/getting-started/install">Installationshandbuch</a>, oder kontaktieren Sie Ihren Hosting-Anbieter."
|
||||
|
||||
msgid "Failed to <strong>CREATE</strong> a test table on your database server with the command %query. The server reports the following message: %error.<p>Are you sure the configured username has the necessary permissions to create tables in the database?</p>"
|
||||
msgstr "<strong>CREATE</strong> ein Test-Tabelle auf Ihrem Datenbankserver mit dem Befehl %query fehlgeschlagen."
|
||||
ENDPO;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\KernelTests\AssertConfigTrait;
|
||||
|
||||
/**
|
||||
* Tests the interactive installer installing the minimal profile.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class MinimalInstallerTest extends ConfigAfterInstallerTestBase {
|
||||
|
||||
use AssertConfigTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'minimal';
|
||||
|
||||
/**
|
||||
* Ensures that the exported minimal configuration is up to date.
|
||||
*/
|
||||
public function testMinimalConfig() {
|
||||
$this->assertInstalledConfig([]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Component\Serialization\Yaml;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Tests multiple distribution profile support.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class MultipleDistributionsProfileTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* The distribution profile info.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $info;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
// Create two distributions.
|
||||
foreach (['distribution_one', 'distribution_two'] as $name) {
|
||||
$info = [
|
||||
'type' => 'profile',
|
||||
'core' => \Drupal::CORE_COMPATIBILITY,
|
||||
'name' => $name . ' profile',
|
||||
'distribution' => [
|
||||
'name' => $name,
|
||||
'install' => [
|
||||
'theme' => 'bartik',
|
||||
],
|
||||
],
|
||||
];
|
||||
// File API functions are not available yet.
|
||||
$path = $this->siteDirectory . '/profiles/' . $name;
|
||||
mkdir($path, 0777, TRUE);
|
||||
file_put_contents("$path/$name.info.yml", Yaml::encode($info));
|
||||
}
|
||||
// Install the first distribution.
|
||||
$this->profile = 'distribution_one';
|
||||
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpLanguage() {
|
||||
// Verify that the distribution name appears.
|
||||
$this->assertRaw('distribution_one');
|
||||
// Verify that the requested theme is used.
|
||||
$this->assertRaw('bartik');
|
||||
// Verify that the "Choose profile" step does not appear.
|
||||
$this->assertNoText('profile');
|
||||
|
||||
parent::setUpLanguage();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is a distribution profile.
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->rootUser->getUsername());
|
||||
|
||||
// Confirm that Drupal recognizes this distribution as the current profile.
|
||||
$this->assertEqual(\Drupal::installProfile(), 'distribution_one');
|
||||
$this->assertEqual(Settings::get('install_profile'), 'distribution_one', 'The install profile has been written to settings.php.');
|
||||
$this->assertEqual($this->config('core.extension')->get('profile'), 'distribution_one', 'The install profile has been written to core.extension configuration.');
|
||||
|
||||
$this->rebuildContainer();
|
||||
$this->pass('Container can be rebuilt as distribution is written to configuration.');
|
||||
$this->assertEqual(\Drupal::installProfile(), 'distribution_one');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\Core\Serialization\Yaml;
|
||||
use Drupal\simpletest\InstallerTestBase;
|
||||
|
||||
/**
|
||||
* Tests distribution profile support.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class SingleVisibleProfileTest extends InstallerTestBase {
|
||||
|
||||
/**
|
||||
* The installation profile to install.
|
||||
*
|
||||
* Not needed when only one is visible.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $profile = NULL;
|
||||
|
||||
protected function setUp() {
|
||||
$profiles = ['standard', 'demo_umami'];
|
||||
foreach ($profiles as $profile) {
|
||||
$info = [
|
||||
'type' => 'profile',
|
||||
'core' => \Drupal::CORE_COMPATIBILITY,
|
||||
'name' => 'Override ' . $profile,
|
||||
'hidden' => TRUE,
|
||||
];
|
||||
// File API functions are not available yet.
|
||||
$path = $this->siteDirectory . '/profiles/' . $profile;
|
||||
mkdir($path, 0777, TRUE);
|
||||
file_put_contents("$path/$profile.info.yml", Yaml::encode($info));
|
||||
}
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpProfile() {
|
||||
// This step is skipped, because there is only one visible profile.
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that the installation succeeded.
|
||||
*/
|
||||
public function testInstalled() {
|
||||
$this->assertUrl('user/1');
|
||||
$this->assertResponse(200);
|
||||
// Confirm that we are logged-in after installation.
|
||||
$this->assertText($this->rootUser->getUsername());
|
||||
// Confirm that the minimal profile was installed.
|
||||
$this->assertEqual(drupal_get_profile(), 'minimal');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests that the site name can be set during a non-interactive installation.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class SiteNameTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* The site name to be used when testing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $siteName;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function installParameters() {
|
||||
$this->siteName = $this->randomMachineName();
|
||||
$parameters = parent::installParameters();
|
||||
$parameters['forms']['install_configure_form']['site_name'] = $this->siteName;
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the desired site name appears on the page after installation.
|
||||
*/
|
||||
public function testSiteName() {
|
||||
$this->drupalGet('');
|
||||
$this->assertRaw($this->siteName, 'The site name that was set during the installation appears on the front page after installation.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\Installer;
|
||||
|
||||
/**
|
||||
* Tests the interactive installer installing the standard profile.
|
||||
*
|
||||
* @group Installer
|
||||
*/
|
||||
class StandardInstallerTest extends ConfigAfterInstallerTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $profile = 'standard';
|
||||
|
||||
/**
|
||||
* Ensures that the user page is available after installation.
|
||||
*/
|
||||
public function testInstaller() {
|
||||
// Verify that the Standard install profile's default frontpage appears.
|
||||
$this->assertRaw('No front page content has been created yet.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpSite() {
|
||||
// Test that the correct theme is being used.
|
||||
$this->assertNoRaw('bartik');
|
||||
$this->assertRaw('themes/seven/css/theme/install-page.css');
|
||||
parent::setUpSite();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function curlExec($curl_options, $redirect = FALSE) {
|
||||
// Ensure that we see the classy progress CSS on the batch page.
|
||||
// Batch processing happens as part of HTTP redirects, so we can access the
|
||||
// HTML of the batch page.
|
||||
if (strpos($curl_options[CURLOPT_URL], '&id=1&op=do_nojs') !== FALSE) {
|
||||
$this->assertRaw('themes/classy/css/components/progress.css');
|
||||
}
|
||||
return parent::curlExec($curl_options, $redirect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the exported standard configuration is up to date.
|
||||
*/
|
||||
public function testStandardConfig() {
|
||||
$skipped_config = [];
|
||||
// \Drupal\simpletest\WebTestBase::installParameters() uses
|
||||
// simpletest@example.com as mail address.
|
||||
$skipped_config['contact.form.feedback'][] = '- simpletest@example.com';
|
||||
// \Drupal\filter\Entity\FilterFormat::toArray() drops the roles of filter
|
||||
// formats.
|
||||
$skipped_config['filter.format.basic_html'][] = 'roles:';
|
||||
$skipped_config['filter.format.basic_html'][] = '- authenticated';
|
||||
$skipped_config['filter.format.full_html'][] = 'roles:';
|
||||
$skipped_config['filter.format.full_html'][] = '- administrator';
|
||||
$skipped_config['filter.format.restricted_html'][] = 'roles:';
|
||||
$skipped_config['filter.format.restricted_html'][] = '- anonymous';
|
||||
|
||||
$this->assertInstalledConfig($skipped_config);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -59,8 +59,9 @@ abstract class ModuleTestBase extends WebTestBase {
|
||||
public function assertModuleTablesExist($module) {
|
||||
$tables = array_keys(drupal_get_module_schema($module));
|
||||
$tables_exist = TRUE;
|
||||
$schema = Database::getConnection()->schema();
|
||||
foreach ($tables as $table) {
|
||||
if (!db_table_exists($table)) {
|
||||
if (!$schema->tableExists($table)) {
|
||||
$tables_exist = FALSE;
|
||||
}
|
||||
}
|
||||
@@ -76,8 +77,9 @@ abstract class ModuleTestBase extends WebTestBase {
|
||||
public function assertModuleTablesDoNotExist($module) {
|
||||
$tables = array_keys(drupal_get_module_schema($module));
|
||||
$tables_exist = FALSE;
|
||||
$schema = Database::getConnection()->schema();
|
||||
foreach ($tables as $table) {
|
||||
if (db_table_exists($table)) {
|
||||
if ($schema->tableExists($table)) {
|
||||
$tables_exist = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,27 +51,26 @@ class UrlAliasFixtures {
|
||||
[
|
||||
'source' => '/node/1',
|
||||
'alias' => '/alias_for_node_1_en',
|
||||
'langcode' => 'en'
|
||||
'langcode' => 'en',
|
||||
],
|
||||
[
|
||||
'source' => '/node/2',
|
||||
'alias' => '/alias_for_node_2_en',
|
||||
'langcode' => 'en'
|
||||
'langcode' => 'en',
|
||||
],
|
||||
[
|
||||
'source' => '/node/1',
|
||||
'alias' => '/alias_for_node_1_fr',
|
||||
'langcode' => 'fr'
|
||||
'langcode' => 'fr',
|
||||
],
|
||||
[
|
||||
'source' => '/node/1',
|
||||
'alias' => '/alias_for_node_1_und',
|
||||
'langcode' => 'und'
|
||||
]
|
||||
'langcode' => 'und',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the table definition for the URL alias fixtures.
|
||||
*
|
||||
|
||||
@@ -57,7 +57,7 @@ class SessionTest extends WebTestBase {
|
||||
// session_test_user_login() which breaks a normal assertion.
|
||||
$edit = [
|
||||
'name' => $user->getUsername(),
|
||||
'pass' => $user->pass_raw
|
||||
'pass' => $user->pass_raw,
|
||||
];
|
||||
$this->drupalPostForm('user/login', $edit, t('Log in'));
|
||||
$this->drupalGet('user');
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\System;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
/**
|
||||
* Tests page access denied functionality, including custom 403 pages.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
class AccessDeniedTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['block', 'node', 'system_test'];
|
||||
|
||||
protected $adminUser;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
|
||||
// Create an administrative user.
|
||||
$this->adminUser = $this->drupalCreateUser(['access administration pages', 'administer site configuration', 'link to any page', 'administer blocks']);
|
||||
$this->adminUser->roles[] = 'administrator';
|
||||
$this->adminUser->save();
|
||||
|
||||
user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, ['access user profiles']);
|
||||
user_role_grant_permissions(RoleInterface::AUTHENTICATED_ID, ['access user profiles']);
|
||||
}
|
||||
|
||||
public function testAccessDenied() {
|
||||
$this->drupalGet('admin');
|
||||
$this->assertText(t('Access denied'), 'Found the default 403 page');
|
||||
$this->assertResponse(403);
|
||||
|
||||
// Ensure that users without permission are denied access and have the
|
||||
// correct path information in drupalSettings.
|
||||
$this->drupalLogin($this->createUser([]));
|
||||
$this->drupalGet('admin', ['query' => ['foo' => 'bar']]);
|
||||
$this->assertEqual($this->drupalSettings['path']['currentPath'], 'admin');
|
||||
$this->assertEqual($this->drupalSettings['path']['currentPathIsAdmin'], TRUE);
|
||||
$this->assertEqual($this->drupalSettings['path']['currentQuery'], ['foo' => 'bar']);
|
||||
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Set a custom 404 page without a starting slash.
|
||||
$edit = [
|
||||
'site_403' => 'user/' . $this->adminUser->id(),
|
||||
];
|
||||
$this->drupalPostForm('admin/config/system/site-information', $edit, t('Save configuration'));
|
||||
$this->assertRaw(SafeMarkup::format("The path '%path' has to start with a slash.", ['%path' => $edit['site_403']]));
|
||||
|
||||
// Use a custom 403 page.
|
||||
$edit = [
|
||||
'site_403' => '/user/' . $this->adminUser->id(),
|
||||
];
|
||||
$this->drupalPostForm('admin/config/system/site-information', $edit, t('Save configuration'));
|
||||
|
||||
// Enable the user login block.
|
||||
$block = $this->drupalPlaceBlock('user_login_block', ['id' => 'login']);
|
||||
|
||||
// Log out and check that the user login block is shown on custom 403 pages.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('admin');
|
||||
$this->assertText($this->adminUser->getUsername(), 'Found the custom 403 page');
|
||||
$this->assertText(t('Username'), 'Blocks are shown on the custom 403 page');
|
||||
|
||||
// Log back in and remove the custom 403 page.
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$edit = [
|
||||
'site_403' => '',
|
||||
];
|
||||
$this->drupalPostForm('admin/config/system/site-information', $edit, t('Save configuration'));
|
||||
|
||||
// Logout and check that the user login block is shown on default 403 pages.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('admin');
|
||||
$this->assertText(t('Access denied'), 'Found the default 403 page');
|
||||
$this->assertResponse(403);
|
||||
$this->assertText(t('Username'), 'Blocks are shown on the default 403 page');
|
||||
|
||||
// Log back in, set the custom 403 page to /user/login and remove the block
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->config('system.site')->set('page.403', '/user/login')->save();
|
||||
$block->disable()->save();
|
||||
|
||||
// Check that we can log in from the 403 page.
|
||||
$this->drupalLogout();
|
||||
$edit = [
|
||||
'name' => $this->adminUser->getUsername(),
|
||||
'pass' => $this->adminUser->pass_raw,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/system/site-information', $edit, t('Log in'));
|
||||
|
||||
// Check that we're still on the same page.
|
||||
$this->assertText(t('Basic site settings'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an inaccessible custom 403 page falls back to the default.
|
||||
*/
|
||||
public function testAccessDeniedCustomPageWithAccessDenied() {
|
||||
// Sets up a 403 page not accessible by the anonymous user.
|
||||
$this->config('system.site')->set('page.403', '/system-test/custom-4xx')->save();
|
||||
|
||||
$this->drupalGet('/system-test/always-denied');
|
||||
$this->assertNoText('Admin-only 4xx response');
|
||||
$this->assertText('You are not authorized to access this page.');
|
||||
$this->assertResponse(403);
|
||||
// Verify the access cacheability metadata for custom 403 is bubbled.
|
||||
$this->assertCacheContext('user.roles');
|
||||
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalGet('/system-test/always-denied');
|
||||
$this->assertText('Admin-only 4xx response');
|
||||
$this->assertResponse(403);
|
||||
// Verify the access cacheability metadata for custom 403 is bubbled.
|
||||
$this->assertCacheContext('user.roles');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\System;
|
||||
|
||||
use Drupal\Core\Menu\MenuTreeParameters;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests output on administrative pages and compact mode functionality.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
class AdminTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* User account with all available permissions
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* User account with limited access to administration pages.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $webUser;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['locale'];
|
||||
|
||||
protected function setUp() {
|
||||
// testAdminPages() requires Locale module.
|
||||
parent::setUp();
|
||||
|
||||
// Create an administrator with all permissions, as well as a regular user
|
||||
// who can only access administration pages and perform some Locale module
|
||||
// administrative tasks, but not all of them.
|
||||
$this->adminUser = $this->drupalCreateUser(array_keys(\Drupal::service('user.permissions')->getPermissions()));
|
||||
$this->webUser = $this->drupalCreateUser([
|
||||
'access administration pages',
|
||||
'translate interface',
|
||||
]);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests output on administrative listing pages.
|
||||
*/
|
||||
public function testAdminPages() {
|
||||
// Go to Administration.
|
||||
$this->drupalGet('admin');
|
||||
|
||||
// Verify that all visible, top-level administration links are listed on
|
||||
// the main administration page.
|
||||
foreach ($this->getTopLevelMenuLinks() as $item) {
|
||||
$this->assertLink($item->getTitle());
|
||||
$this->assertLinkByHref($item->getUrlObject()->toString());
|
||||
// The description should appear below the link.
|
||||
$this->assertText($item->getDescription());
|
||||
}
|
||||
|
||||
// For each administrative listing page on which the Locale module appears,
|
||||
// verify that there are links to the module's primary configuration pages,
|
||||
// but no links to its individual sub-configuration pages. Also verify that
|
||||
// a user with access to only some Locale module administration pages only
|
||||
// sees links to the pages they have access to.
|
||||
$admin_list_pages = [
|
||||
'admin/index',
|
||||
'admin/config',
|
||||
'admin/config/regional',
|
||||
];
|
||||
|
||||
foreach ($admin_list_pages as $page) {
|
||||
// For the administrator, verify that there are links to Locale's primary
|
||||
// configuration pages, but no links to individual sub-configuration
|
||||
// pages.
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalGet($page);
|
||||
$this->assertLinkByHref('admin/config');
|
||||
$this->assertLinkByHref('admin/config/regional/settings');
|
||||
$this->assertLinkByHref('admin/config/regional/date-time');
|
||||
$this->assertLinkByHref('admin/config/regional/language');
|
||||
$this->assertNoLinkByHref('admin/config/regional/language/detection/session');
|
||||
$this->assertNoLinkByHref('admin/config/regional/language/detection/url');
|
||||
$this->assertLinkByHref('admin/config/regional/translate');
|
||||
// On admin/index only, the administrator should also see a "Configure
|
||||
// permissions" link for the Locale module.
|
||||
if ($page == 'admin/index') {
|
||||
$this->assertLinkByHref("admin/people/permissions#module-locale");
|
||||
}
|
||||
|
||||
// For a less privileged user, verify that there are no links to Locale's
|
||||
// primary configuration pages, but a link to the translate page exists.
|
||||
$this->drupalLogin($this->webUser);
|
||||
$this->drupalGet($page);
|
||||
$this->assertLinkByHref('admin/config');
|
||||
$this->assertNoLinkByHref('admin/config/regional/settings');
|
||||
$this->assertNoLinkByHref('admin/config/regional/date-time');
|
||||
$this->assertNoLinkByHref('admin/config/regional/language');
|
||||
$this->assertNoLinkByHref('admin/config/regional/language/detection/session');
|
||||
$this->assertNoLinkByHref('admin/config/regional/language/detection/url');
|
||||
$this->assertLinkByHref('admin/config/regional/translate');
|
||||
// This user cannot configure permissions, so even on admin/index should
|
||||
// not see a "Configure permissions" link for the Locale module.
|
||||
if ($page == 'admin/index') {
|
||||
$this->assertNoLinkByHref("admin/people/permissions#module-locale");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all top level menu links.
|
||||
*
|
||||
* @return \Drupal\Core\Menu\MenuLinkInterface[]
|
||||
*/
|
||||
protected function getTopLevelMenuLinks() {
|
||||
$menu_tree = \Drupal::menuTree();
|
||||
|
||||
// The system.admin link is normally the parent of all top-level admin links.
|
||||
$parameters = new MenuTreeParameters();
|
||||
$parameters->setRoot('system.admin')->excludeRoot()->setTopLevelOnly()->onlyEnabledLinks();
|
||||
$tree = $menu_tree->load(NULL, $parameters);
|
||||
$manipulators = [
|
||||
['callable' => 'menu.default_tree_manipulators:checkAccess'],
|
||||
['callable' => 'menu.default_tree_manipulators:flatten'],
|
||||
];
|
||||
$tree = $menu_tree->transform($tree, $manipulators);
|
||||
|
||||
// Transform the tree to a list of menu links.
|
||||
$menu_links = [];
|
||||
foreach ($tree as $element) {
|
||||
$menu_links[] = $element->link;
|
||||
}
|
||||
|
||||
return $menu_links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test compact mode.
|
||||
*/
|
||||
public function testCompactMode() {
|
||||
// The front page defaults to 'user/login', which redirects to 'user/{user}'
|
||||
// for authenticated users. We cannot use '<front>', since this does not
|
||||
// match the redirected url.
|
||||
$frontpage_url = 'user/' . $this->adminUser->id();
|
||||
|
||||
$this->drupalGet('admin/compact/on');
|
||||
$this->assertResponse(200, 'A valid page is returned after turning on compact mode.');
|
||||
$this->assertUrl($frontpage_url, [], 'The user is redirected to the front page after turning on compact mode.');
|
||||
$this->assertTrue($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'Compact mode turns on.');
|
||||
$this->drupalGet('admin/compact/on');
|
||||
$this->assertTrue($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'Compact mode remains on after a repeat call.');
|
||||
$this->drupalGet('');
|
||||
$this->assertTrue($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'Compact mode persists on new requests.');
|
||||
|
||||
$this->drupalGet('admin/compact/off');
|
||||
$this->assertResponse(200, 'A valid page is returned after turning off compact mode.');
|
||||
$this->assertUrl($frontpage_url, [], 'The user is redirected to the front page after turning off compact mode.');
|
||||
$this->assertEqual($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'deleted', 'Compact mode turns off.');
|
||||
$this->drupalGet('admin/compact/off');
|
||||
$this->assertEqual($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'deleted', 'Compact mode remains off after a repeat call.');
|
||||
$this->drupalGet('');
|
||||
$this->assertTrue($this->cookies['Drupal.visitor.admin_compact_mode']['value'], 'Compact mode persists on new requests.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\System;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests cron runs.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
class CronRunTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['common_test', 'common_test_cron_helper', 'automated_cron'];
|
||||
|
||||
/**
|
||||
* Test cron runs.
|
||||
*/
|
||||
public function testCronRun() {
|
||||
// Run cron anonymously without any cron key.
|
||||
$this->drupalGet('cron');
|
||||
$this->assertResponse(404);
|
||||
|
||||
// Run cron anonymously with a random cron key.
|
||||
$key = $this->randomMachineName(16);
|
||||
$this->drupalGet('cron/' . $key);
|
||||
$this->assertResponse(403);
|
||||
|
||||
// Run cron anonymously with the valid cron key.
|
||||
$key = \Drupal::state()->get('system.cron_key');
|
||||
$this->drupalGet('cron/' . $key);
|
||||
$this->assertResponse(204);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the automated cron run module is working.
|
||||
*
|
||||
* In these tests we do not use REQUEST_TIME to track start time, because we
|
||||
* need the exact time when cron is triggered.
|
||||
*/
|
||||
public function testAutomatedCron() {
|
||||
// Test with a logged in user; anonymous users likely don't cause Drupal to
|
||||
// fully bootstrap, because of the internal page cache or an external
|
||||
// reverse proxy. Reuse this user for disabling cron later in the test.
|
||||
$admin_user = $this->drupalCreateUser(['administer site configuration']);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Ensure cron does not run when a non-zero cron interval is specified and
|
||||
// was not passed.
|
||||
$cron_last = time();
|
||||
$cron_safe_interval = 100;
|
||||
\Drupal::state()->set('system.cron_last', $cron_last);
|
||||
$this->config('automated_cron.settings')
|
||||
->set('interval', $cron_safe_interval)
|
||||
->save();
|
||||
$this->drupalGet('');
|
||||
$this->assertTrue($cron_last == \Drupal::state()->get('system.cron_last'), 'Cron does not run when the cron interval is not passed.');
|
||||
|
||||
// Test if cron runs when the cron interval was passed.
|
||||
$cron_last = time() - 200;
|
||||
\Drupal::state()->set('system.cron_last', $cron_last);
|
||||
$this->drupalGet('');
|
||||
sleep(1);
|
||||
$this->assertTrue($cron_last < \Drupal::state()->get('system.cron_last'), 'Cron runs when the cron interval is passed.');
|
||||
|
||||
// Disable cron through the interface by setting the interval to zero.
|
||||
$this->drupalPostForm('admin/config/system/cron', ['interval' => 0], t('Save configuration'));
|
||||
$this->assertText(t('The configuration options have been saved.'));
|
||||
$this->drupalLogout();
|
||||
|
||||
// Test if cron does not run when the cron interval is set to zero.
|
||||
$cron_last = time() - 200;
|
||||
\Drupal::state()->set('system.cron_last', $cron_last);
|
||||
$this->drupalGet('');
|
||||
$this->assertTrue($cron_last == \Drupal::state()->get('system.cron_last'), 'Cron does not run when the cron threshold is disabled.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure exceptions thrown on hook_cron() don't affect other modules.
|
||||
*/
|
||||
public function testCronExceptions() {
|
||||
\Drupal::state()->delete('common_test.cron');
|
||||
// The common_test module throws an exception. If it isn't caught, the tests
|
||||
// won't finish successfully.
|
||||
// The common_test_cron_helper module sets the 'common_test_cron' variable.
|
||||
$this->cronRun();
|
||||
$result = \Drupal::state()->get('common_test.cron');
|
||||
$this->assertEqual($result, 'success', 'Cron correctly handles exceptions thrown during hook_cron() invocations.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the cron UI reads from the state storage.
|
||||
*/
|
||||
public function testCronUI() {
|
||||
$admin_user = $this->drupalCreateUser(['administer site configuration']);
|
||||
$this->drupalLogin($admin_user);
|
||||
$this->drupalGet('admin/config/system/cron');
|
||||
// Don't use REQUEST to calculate the exact time, because that will
|
||||
// fail randomly. Look for the word 'years', because without a timestamp,
|
||||
// the time will start at 1 January 1970.
|
||||
$this->assertNoText('years');
|
||||
|
||||
$cron_last = time() - 200;
|
||||
\Drupal::state()->set('system.cron_last', $cron_last);
|
||||
|
||||
$this->drupalPostForm(NULL, [], 'Save configuration');
|
||||
$this->assertText('The configuration options have been saved.');
|
||||
$this->assertUrl('admin/config/system/cron');
|
||||
|
||||
// Check that cron does not run when saving the configuration form.
|
||||
$this->assertEqual($cron_last, \Drupal::state()->get('system.cron_last'), 'Cron does not run when saving the configuration form.');
|
||||
|
||||
// Check that cron runs when triggered manually.
|
||||
$this->drupalPostForm(NULL, [], 'Run cron');
|
||||
$this->assertTrue($cron_last < \Drupal::state()->get('system.cron_last'), 'Cron runs when triggered manually.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the manual cron run is working.
|
||||
*/
|
||||
public function testManualCron() {
|
||||
$admin_user = $this->drupalCreateUser(['administer site configuration']);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
$this->drupalGet('admin/reports/status/run-cron');
|
||||
$this->assertResponse(403);
|
||||
|
||||
$this->drupalGet('admin/reports/status');
|
||||
$this->clickLink(t('Run cron'));
|
||||
$this->assertResponse(200);
|
||||
$this->assertText(t('Cron ran successfully.'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\System;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Confirm that the default mobile meta tags appear as expected.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
class DefaultMobileMetaTagsTest extends WebTestBase {
|
||||
/**
|
||||
* Array of default meta tags to insert into the page.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $defaultMetaTags;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->defaultMetaTags = [
|
||||
'viewport' => '<meta name="viewport" content="width=device-width, initial-scale=1.0" />',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the default mobile meta tags are added.
|
||||
*/
|
||||
public function testDefaultMetaTagsExist() {
|
||||
$this->drupalGet('');
|
||||
foreach ($this->defaultMetaTags as $name => $metatag) {
|
||||
$this->assertRaw($metatag, SafeMarkup::format('Default Mobile meta tag "@name" displayed properly.', ['@name' => $name]), 'System');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the default mobile meta tags can be removed.
|
||||
*/
|
||||
public function testRemovingDefaultMetaTags() {
|
||||
\Drupal::service('module_installer')->install(['system_module_test']);
|
||||
$this->drupalGet('');
|
||||
foreach ($this->defaultMetaTags as $name => $metatag) {
|
||||
$this->assertNoRaw($metatag, SafeMarkup::format('Default Mobile meta tag "@name" removed properly.', ['@name' => $name]), 'System');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\System;
|
||||
|
||||
use Drupal\Core\Flood\DatabaseBackend;
|
||||
use Drupal\Core\Flood\MemoryBackend;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Functional tests for the flood control mechanism.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
class FloodTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Flood backends need a request object. Create a dummy one and insert it
|
||||
// to the container.
|
||||
$request = Request::createFromGlobals();
|
||||
$this->container->get('request_stack')->push($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test flood control mechanism clean-up.
|
||||
*/
|
||||
public function testCleanUp() {
|
||||
$threshold = 1;
|
||||
$window_expired = -1;
|
||||
$name = 'flood_test_cleanup';
|
||||
|
||||
$flood = \Drupal::flood();
|
||||
$this->assertTrue($flood->isAllowed($name, $threshold));
|
||||
// Register expired event.
|
||||
$flood->register($name, $window_expired);
|
||||
// Verify event is not allowed.
|
||||
$this->assertFalse($flood->isAllowed($name, $threshold));
|
||||
// Run cron and verify event is now allowed.
|
||||
$this->cronRun();
|
||||
$this->assertTrue($flood->isAllowed($name, $threshold));
|
||||
|
||||
// Register unexpired event.
|
||||
$flood->register($name);
|
||||
// Verify event is not allowed.
|
||||
$this->assertFalse($flood->isAllowed($name, $threshold));
|
||||
// Run cron and verify event is still not allowed.
|
||||
$this->cronRun();
|
||||
$this->assertFalse($flood->isAllowed($name, $threshold));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test flood control memory backend.
|
||||
*/
|
||||
public function testMemoryBackend() {
|
||||
$threshold = 1;
|
||||
$window_expired = -1;
|
||||
$name = 'flood_test_cleanup';
|
||||
|
||||
$request_stack = \Drupal::service('request_stack');
|
||||
$flood = new MemoryBackend($request_stack);
|
||||
$this->assertTrue($flood->isAllowed($name, $threshold));
|
||||
// Register expired event.
|
||||
$flood->register($name, $window_expired);
|
||||
// Verify event is not allowed.
|
||||
$this->assertFalse($flood->isAllowed($name, $threshold));
|
||||
// Run cron and verify event is now allowed.
|
||||
$flood->garbageCollection();
|
||||
$this->assertTrue($flood->isAllowed($name, $threshold));
|
||||
|
||||
// Register unexpired event.
|
||||
$flood->register($name);
|
||||
// Verify event is not allowed.
|
||||
$this->assertFalse($flood->isAllowed($name, $threshold));
|
||||
// Run cron and verify event is still not allowed.
|
||||
$flood->garbageCollection();
|
||||
$this->assertFalse($flood->isAllowed($name, $threshold));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test flood control database backend.
|
||||
*/
|
||||
public function testDatabaseBackend() {
|
||||
$threshold = 1;
|
||||
$window_expired = -1;
|
||||
$name = 'flood_test_cleanup';
|
||||
|
||||
$connection = \Drupal::service('database');
|
||||
$request_stack = \Drupal::service('request_stack');
|
||||
$flood = new DatabaseBackend($connection, $request_stack);
|
||||
$this->assertTrue($flood->isAllowed($name, $threshold));
|
||||
// Register expired event.
|
||||
$flood->register($name, $window_expired);
|
||||
// Verify event is not allowed.
|
||||
$this->assertFalse($flood->isAllowed($name, $threshold));
|
||||
// Run cron and verify event is now allowed.
|
||||
$flood->garbageCollection();
|
||||
$this->assertTrue($flood->isAllowed($name, $threshold));
|
||||
|
||||
// Register unexpired event.
|
||||
$flood->register($name);
|
||||
// Verify event is not allowed.
|
||||
$this->assertFalse($flood->isAllowed($name, $threshold));
|
||||
// Run cron and verify event is still not allowed.
|
||||
$flood->garbageCollection();
|
||||
$this->assertFalse($flood->isAllowed($name, $threshold));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\System;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests front page functionality and administration.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
class FrontPageTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'system_test', 'views'];
|
||||
|
||||
/**
|
||||
* The path to a node that is created for testing.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $nodePath;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create admin user, log in admin user, and create one node.
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'access content',
|
||||
'administer site configuration',
|
||||
]));
|
||||
$this->drupalCreateContentType(['type' => 'page']);
|
||||
$this->nodePath = "node/" . $this->drupalCreateNode(['promote' => 1])->id();
|
||||
|
||||
// Configure 'node' as front page.
|
||||
$this->config('system.site')->set('page.front', '/node')->save();
|
||||
// Enable front page logging in system_test.module.
|
||||
\Drupal::state()->set('system_test.front_page_output', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test front page functionality.
|
||||
*/
|
||||
public function testDrupalFrontPage() {
|
||||
// Create a promoted node to test the <title> tag on the front page view.
|
||||
$settings = [
|
||||
'title' => $this->randomMachineName(8),
|
||||
'promote' => 1,
|
||||
];
|
||||
$this->drupalCreateNode($settings);
|
||||
$this->drupalGet('');
|
||||
$this->assertTitle('Home | Drupal');
|
||||
|
||||
$this->assertText(t('On front page.'), 'Path is the front page.');
|
||||
$this->drupalGet('node');
|
||||
$this->assertText(t('On front page.'), 'Path is the front page.');
|
||||
$this->drupalGet($this->nodePath);
|
||||
$this->assertNoText(t('On front page.'), 'Path is not the front page.');
|
||||
|
||||
// Change the front page to an invalid path.
|
||||
$edit = ['site_frontpage' => '/kittens'];
|
||||
$this->drupalPostForm('admin/config/system/site-information', $edit, t('Save configuration'));
|
||||
$this->assertText(t("Either the path '@path' is invalid or you do not have access to it.", ['@path' => $edit['site_frontpage']]));
|
||||
|
||||
// Change the front page to a path without a starting slash.
|
||||
$edit = ['site_frontpage' => $this->nodePath];
|
||||
$this->drupalPostForm('admin/config/system/site-information', $edit, t('Save configuration'));
|
||||
$this->assertRaw(SafeMarkup::format("The path '%path' has to start with a slash.", ['%path' => $edit['site_frontpage']]));
|
||||
|
||||
// Change the front page to a valid path.
|
||||
$edit['site_frontpage'] = '/' . $this->nodePath;
|
||||
$this->drupalPostForm('admin/config/system/site-information', $edit, t('Save configuration'));
|
||||
$this->assertText(t('The configuration options have been saved.'), 'The front page path has been saved.');
|
||||
|
||||
$this->drupalGet('');
|
||||
$this->assertText(t('On front page.'), 'Path is the front page.');
|
||||
$this->drupalGet('node');
|
||||
$this->assertNoText(t('On front page.'), 'Path is not the front page.');
|
||||
$this->drupalGet($this->nodePath);
|
||||
$this->assertText(t('On front page.'), 'Path is the front page.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\System;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests .htaccess is working correctly.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
class HtaccessTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'path'];
|
||||
|
||||
/**
|
||||
* Get an array of file paths for access testing.
|
||||
*
|
||||
* @return int[]
|
||||
* An array keyed by file paths. Each value is the expected response code,
|
||||
* for example, 200 or 403.
|
||||
*/
|
||||
protected function getProtectedFiles() {
|
||||
$path = drupal_get_path('module', 'system') . '/tests/fixtures/HtaccessTest';
|
||||
|
||||
// Tests the FilesMatch directive which denies access to certain file
|
||||
// extensions.
|
||||
$file_exts_to_deny = [
|
||||
'engine',
|
||||
'inc',
|
||||
'install',
|
||||
'make',
|
||||
'module',
|
||||
'module~',
|
||||
'module.bak',
|
||||
'module.orig',
|
||||
'module.save',
|
||||
'module.swo',
|
||||
'module.swp',
|
||||
'php~',
|
||||
'php.bak',
|
||||
'php.orig',
|
||||
'php.save',
|
||||
'php.swo',
|
||||
'php.swp',
|
||||
'profile',
|
||||
'po',
|
||||
'sh',
|
||||
'sql',
|
||||
'theme',
|
||||
'twig',
|
||||
'tpl.php',
|
||||
'xtmpl',
|
||||
'yml',
|
||||
];
|
||||
|
||||
foreach ($file_exts_to_deny as $file_ext) {
|
||||
$file_paths["$path/access_test.$file_ext"] = 403;
|
||||
}
|
||||
|
||||
// Tests the .htaccess file in vendor and created by a Composer script.
|
||||
// Try and access a non PHP file in the vendor directory.
|
||||
// @see Drupal\\Core\\Composer\\Composer::ensureHtaccess
|
||||
$file_paths['vendor/composer/installed.json'] = 403;
|
||||
|
||||
// Tests the rewrite conditions and rule that denies access to php files.
|
||||
$file_paths['core/lib/Drupal.php'] = 403;
|
||||
$file_paths['vendor/autoload.php'] = 403;
|
||||
$file_paths['autoload.php'] = 403;
|
||||
|
||||
// Test extensions that should be permitted.
|
||||
$file_exts_to_allow = [
|
||||
'php-info.txt'
|
||||
];
|
||||
|
||||
foreach ($file_exts_to_allow as $file_ext) {
|
||||
$file_paths["$path/access_test.$file_ext"] = 200;
|
||||
}
|
||||
|
||||
// Ensure composer.json and composer.lock cannot be accessed.
|
||||
$file_paths["$path/composer.json"] = 403;
|
||||
$file_paths["$path/composer.lock"] = 403;
|
||||
|
||||
return $file_paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over protected files and calls assertNoFileAccess().
|
||||
*/
|
||||
public function testFileAccess() {
|
||||
foreach ($this->getProtectedFiles() as $file => $response_code) {
|
||||
$this->assertFileAccess($file, $response_code);
|
||||
}
|
||||
|
||||
// Test that adding "/1" to a .php URL does not make it accessible.
|
||||
$this->drupalGet('core/lib/Drupal.php/1');
|
||||
$this->assertResponse(403, "Access to core/lib/Drupal.php/1 is denied.");
|
||||
|
||||
// Test that it is possible to have path aliases containing .php.
|
||||
$type = $this->drupalCreateContentType();
|
||||
|
||||
// Create an node aliased to test.php.
|
||||
$node = $this->drupalCreateNode([
|
||||
'title' => 'This is a node',
|
||||
'type' => $type->id(),
|
||||
'path' => '/test.php'
|
||||
]);
|
||||
$node->save();
|
||||
$this->drupalGet('test.php');
|
||||
$this->assertResponse(200);
|
||||
$this->assertText('This is a node');
|
||||
|
||||
// Update node's alias to test.php/test.
|
||||
$node->path = '/test.php/test';
|
||||
$node->save();
|
||||
$this->drupalGet('test.php/test');
|
||||
$this->assertResponse(200);
|
||||
$this->assertText('This is a node');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a file exists and requesting it returns a specific response.
|
||||
*
|
||||
* @param string $path
|
||||
* Path to file. Without leading slash.
|
||||
* @param int $response_code
|
||||
* The expected response code. For example: 200, 403 or 404.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the assertion succeeded, FALSE otherwise.
|
||||
*/
|
||||
protected function assertFileAccess($path, $response_code) {
|
||||
$result = $this->assertTrue(file_exists(\Drupal::root() . '/' . $path), "The file $path exists.");
|
||||
$this->drupalGet($path);
|
||||
$result = $result && $this->assertResponse($response_code, "Response code to $path is $response_code.");
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SVGZ files are served with Content-Encoding: gzip.
|
||||
*/
|
||||
public function testSvgzContentEncoding() {
|
||||
$this->drupalGet('core/modules/system/tests/logo.svgz');
|
||||
$this->assertResponse(200);
|
||||
$header = $this->drupalGetHeader('Content-Encoding');
|
||||
$this->assertEqual($header, 'gzip');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\System;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
/**
|
||||
* Tests page not found functionality, including custom 404 pages.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
class PageNotFoundTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['system_test'];
|
||||
|
||||
protected $adminUser;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create an administrative user.
|
||||
$this->adminUser = $this->drupalCreateUser(['administer site configuration', 'link to any page']);
|
||||
$this->adminUser->roles[] = 'administrator';
|
||||
$this->adminUser->save();
|
||||
|
||||
user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, ['access user profiles']);
|
||||
user_role_grant_permissions(RoleInterface::AUTHENTICATED_ID, ['access user profiles']);
|
||||
}
|
||||
|
||||
public function testPageNotFound() {
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalGet($this->randomMachineName(10));
|
||||
$this->assertText(t('Page not found'), 'Found the default 404 page');
|
||||
|
||||
// Set a custom 404 page without a starting slash.
|
||||
$edit = [
|
||||
'site_404' => 'user/' . $this->adminUser->id(),
|
||||
];
|
||||
$this->drupalPostForm('admin/config/system/site-information', $edit, t('Save configuration'));
|
||||
$this->assertRaw(SafeMarkup::format("The path '%path' has to start with a slash.", ['%path' => $edit['site_404']]));
|
||||
|
||||
// Use a custom 404 page.
|
||||
$edit = [
|
||||
'site_404' => '/user/' . $this->adminUser->id(),
|
||||
];
|
||||
$this->drupalPostForm('admin/config/system/site-information', $edit, t('Save configuration'));
|
||||
|
||||
$this->drupalGet($this->randomMachineName(10));
|
||||
$this->assertText($this->adminUser->getUsername(), 'Found the custom 404 page');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an inaccessible custom 404 page falls back to the default.
|
||||
*/
|
||||
public function testPageNotFoundCustomPageWithAccessDenied() {
|
||||
// Sets up a 404 page not accessible by the anonymous user.
|
||||
$this->config('system.site')->set('page.404', '/system-test/custom-4xx')->save();
|
||||
|
||||
$this->drupalGet('/this-path-does-not-exist');
|
||||
$this->assertNoText('Admin-only 4xx response');
|
||||
$this->assertText('The requested page could not be found.');
|
||||
$this->assertResponse(404);
|
||||
// Verify the access cacheability metadata for custom 404 is bubbled.
|
||||
$this->assertCacheContext('user.roles');
|
||||
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalGet('/this-path-does-not-exist');
|
||||
$this->assertText('Admin-only 4xx response');
|
||||
$this->assertNoText('The requested page could not be found.');
|
||||
$this->assertResponse(404);
|
||||
// Verify the access cacheability metadata for custom 404 is bubbled.
|
||||
$this->assertCacheContext('user.roles');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\System;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests HTML output escaping of page title, site name, and slogan.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
class PageTitleTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'test_page_test', 'form_test', 'block'];
|
||||
|
||||
protected $contentUser;
|
||||
protected $savedTitle;
|
||||
|
||||
/**
|
||||
* Implement setUp().
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
|
||||
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
|
||||
$this->contentUser = $this->drupalCreateUser(['create page content', 'access content', 'administer themes', 'administer site configuration', 'link to any page']);
|
||||
$this->drupalLogin($this->contentUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the handling of HTML in node titles.
|
||||
*/
|
||||
public function testTitleTags() {
|
||||
$title = "string with <em>HTML</em>";
|
||||
// Generate node content.
|
||||
$edit = [
|
||||
'title[0][value]' => '!SimpleTest! ' . $title . $this->randomMachineName(20),
|
||||
'body[0][value]' => '!SimpleTest! test body' . $this->randomMachineName(200),
|
||||
];
|
||||
// Create the node with HTML in the title.
|
||||
$this->drupalPostForm('node/add/page', $edit, t('Save'));
|
||||
|
||||
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
|
||||
$this->assertNotNull($node, 'Node created and found in database');
|
||||
$this->assertText(Html::escape($edit['title[0][value]']), 'Check to make sure tags in the node title are converted.');
|
||||
$this->drupalGet("node/" . $node->id());
|
||||
$this->assertText(Html::escape($edit['title[0][value]']), 'Check to make sure tags in the node title are converted.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the title of the site is XSS proof.
|
||||
*/
|
||||
public function testTitleXSS() {
|
||||
// Set some title with JavaScript and HTML chars to escape.
|
||||
$title = '</title><script type="text/javascript">alert("Title XSS!");</script> & < > " \' ';
|
||||
$title_filtered = Html::escape($title);
|
||||
|
||||
$slogan = '<script type="text/javascript">alert("Slogan XSS!");</script>';
|
||||
$slogan_filtered = Xss::filterAdmin($slogan);
|
||||
|
||||
// Set title and slogan.
|
||||
$edit = [
|
||||
'site_name' => $title,
|
||||
'site_slogan' => $slogan,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/system/site-information', $edit, t('Save configuration'));
|
||||
|
||||
// Place branding block with site name and slogan into header region.
|
||||
$this->drupalPlaceBlock('system_branding_block', ['region' => 'header']);
|
||||
|
||||
// Load frontpage.
|
||||
$this->drupalGet('');
|
||||
|
||||
// Test the title.
|
||||
$this->assertNoRaw($title, 'Check for the lack of the unfiltered version of the title.');
|
||||
// Add </title> to make sure we're checking the title tag, rather than the
|
||||
// first 'heading' on the page.
|
||||
$this->assertRaw($title_filtered . '</title>', 'Check for the filtered version of the title in a <title> tag.');
|
||||
|
||||
// Test the slogan.
|
||||
$this->assertNoRaw($slogan, 'Check for the unfiltered version of the slogan.');
|
||||
$this->assertRaw($slogan_filtered, 'Check for the filtered version of the slogan.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the page title of render arrays.
|
||||
*
|
||||
* @see \Drupal\test_page_test\Controller\Test
|
||||
*/
|
||||
public function testRoutingTitle() {
|
||||
// Test the '#title' render array attribute.
|
||||
$this->drupalGet('test-render-title');
|
||||
|
||||
$this->assertTitle('Foo | Drupal');
|
||||
$result = $this->xpath('//h1[@class="page-title"]');
|
||||
$this->assertEqual('Foo', (string) $result[0]);
|
||||
|
||||
// Test forms
|
||||
$this->drupalGet('form-test/object-builder');
|
||||
|
||||
$this->assertTitle('Test dynamic title | Drupal');
|
||||
$result = $this->xpath('//h1[@class="page-title"]');
|
||||
$this->assertEqual('Test dynamic title', (string) $result[0]);
|
||||
|
||||
// Set some custom translated strings.
|
||||
$this->addCustomTranslations('en', [
|
||||
'' => ['Static title' => 'Static title translated'],
|
||||
]);
|
||||
$this->writeCustomTranslations();
|
||||
|
||||
// Ensure that the title got translated.
|
||||
$this->drupalGet('test-page-static-title');
|
||||
|
||||
$this->assertTitle('Static title translated | Drupal');
|
||||
$result = $this->xpath('//h1[@class="page-title"]');
|
||||
$this->assertEqual('Static title translated', (string) $result[0]);
|
||||
|
||||
// Test the dynamic '_title_callback' route option.
|
||||
$this->drupalGet('test-page-dynamic-title');
|
||||
|
||||
$this->assertTitle('Dynamic title | Drupal');
|
||||
$result = $this->xpath('//h1[@class="page-title"]');
|
||||
$this->assertEqual('Dynamic title', (string) $result[0]);
|
||||
|
||||
// Ensure that titles are cacheable and are escaped normally if the
|
||||
// controller does not escape them.
|
||||
$this->drupalGet('test-page-cached-controller');
|
||||
$this->assertTitle('Cached title | Drupal');
|
||||
$this->assertRaw(Html::escape('<span>Cached title</span>') . '</h1>');
|
||||
$this->drupalGet('test-page-cached-controller');
|
||||
$this->assertTitle('Cached title | Drupal');
|
||||
$this->assertRaw(Html::escape('<span>Cached title</span>') . '</h1>');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\System;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Functional tests shutdown functions.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
class ShutdownFunctionsTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['system_test'];
|
||||
|
||||
protected function tearDown() {
|
||||
// This test intentionally throws an exception in a PHP shutdown function.
|
||||
// Prevent it from being interpreted as an actual test failure.
|
||||
// Not using File API; a potential error must trigger a PHP warning.
|
||||
unlink(\Drupal::root() . '/' . $this->siteDirectory . '/error.log');
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test shutdown functions.
|
||||
*/
|
||||
public function testShutdownFunctions() {
|
||||
$arg1 = $this->randomMachineName();
|
||||
$arg2 = $this->randomMachineName();
|
||||
$this->drupalGet('system-test/shutdown-functions/' . $arg1 . '/' . $arg2);
|
||||
|
||||
// If using PHP-FPM then fastcgi_finish_request() will have been fired
|
||||
// returning the response before shutdown functions have fired.
|
||||
// @see \Drupal\system_test\Controller\SystemTestController::shutdownFunctions()
|
||||
$server_using_fastcgi = strpos($this->getRawContent(), 'The function fastcgi_finish_request exists when serving the request.');
|
||||
if ($server_using_fastcgi) {
|
||||
// We need to wait to ensure that the shutdown functions have fired.
|
||||
sleep(1);
|
||||
}
|
||||
$this->assertEqual(\Drupal::state()->get('_system_test_first_shutdown_function'), [$arg1, $arg2]);
|
||||
$this->assertEqual(\Drupal::state()->get('_system_test_second_shutdown_function'), [$arg1, $arg2]);
|
||||
|
||||
if (!$server_using_fastcgi) {
|
||||
// Make sure exceptions displayed through
|
||||
// \Drupal\Core\Utility\Error::renderExceptionSafe() are correctly
|
||||
// escaped.
|
||||
$this->assertRaw('Drupal is <blink>awesome</blink>.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\System;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests access to site while in maintenance mode.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
class SiteMaintenanceTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node'];
|
||||
|
||||
protected $adminUser;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Configure 'node' as front page.
|
||||
$this->config('system.site')->set('page.front', '/node')->save();
|
||||
$this->config('system.performance')->set('js.preprocess', 1)->save();
|
||||
|
||||
// Create a user allowed to access site in maintenance mode.
|
||||
$this->user = $this->drupalCreateUser(['access site in maintenance mode']);
|
||||
// Create an administrative user.
|
||||
$this->adminUser = $this->drupalCreateUser(['administer site configuration', 'access site in maintenance mode']);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies site maintenance mode functionality.
|
||||
*/
|
||||
public function testSiteMaintenance() {
|
||||
|
||||
// Verify that permission message is displayed.
|
||||
$permission_handler = $this->container->get('user.permissions');
|
||||
$permissions = $permission_handler->getPermissions();
|
||||
$permission_label = $permissions['access site in maintenance mode']['title'];
|
||||
$permission_message = t('Visitors will only see the maintenance mode message. Only users with the "@permission-label" <a href=":permissions-url">permission</a> will be able to access the site. Authorized users can log in directly via the <a href=":user-login">user login</a> page.', ['@permission-label' => $permission_label, ':permissions-url' => \Drupal::url('user.admin_permissions'), ':user-login' => \Drupal::url('user.login')]);
|
||||
$this->drupalGet(Url::fromRoute('system.site_maintenance_mode'));
|
||||
$this->assertRaw($permission_message, 'Found the permission message.');
|
||||
|
||||
$this->drupalGet(Url::fromRoute('user.page'));
|
||||
// JS should be aggregated, so drupal.js is not in the page source.
|
||||
$links = $this->xpath('//script[contains(@src, :href)]', [':href' => '/core/misc/drupal.js']);
|
||||
$this->assertFalse(isset($links[0]), 'script /core/misc/drupal.js not in page');
|
||||
// Turn on maintenance mode.
|
||||
$edit = [
|
||||
'maintenance_mode' => 1,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/development/maintenance', $edit, t('Save configuration'));
|
||||
|
||||
$admin_message = t('Operating in maintenance mode. <a href=":url">Go online.</a>', [':url' => \Drupal::url('system.site_maintenance_mode')]);
|
||||
$user_message = t('Operating in maintenance mode.');
|
||||
$offline_message = t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', ['@site' => $this->config('system.site')->get('name')]);
|
||||
|
||||
$this->drupalGet(Url::fromRoute('user.page'));
|
||||
// JS should not be aggregated, so drupal.js is expected in the page source.
|
||||
$links = $this->xpath('//script[contains(@src, :href)]', [':href' => '/core/misc/drupal.js']);
|
||||
$this->assertTrue(isset($links[0]), 'script /core/misc/drupal.js in page');
|
||||
$this->assertRaw($admin_message, 'Found the site maintenance mode message.');
|
||||
|
||||
// Logout and verify that offline message is displayed.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('');
|
||||
$this->assertEqual('Site under maintenance', $this->cssSelect('main h1')[0]);
|
||||
$this->assertText($offline_message);
|
||||
$this->drupalGet('node');
|
||||
$this->assertEqual('Site under maintenance', $this->cssSelect('main h1')[0]);
|
||||
$this->assertText($offline_message);
|
||||
$this->drupalGet('user/register');
|
||||
$this->assertEqual('Site under maintenance', $this->cssSelect('main h1')[0]);
|
||||
$this->assertText($offline_message);
|
||||
|
||||
// Verify that user is able to log in.
|
||||
$this->drupalGet('user');
|
||||
$this->assertNoText($offline_message);
|
||||
$this->drupalGet('user/login');
|
||||
$this->assertNoText($offline_message);
|
||||
|
||||
// Log in user and verify that maintenance mode message is displayed
|
||||
// directly after login.
|
||||
$edit = [
|
||||
'name' => $this->user->getUsername(),
|
||||
'pass' => $this->user->pass_raw,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Log in'));
|
||||
$this->assertText($user_message);
|
||||
|
||||
// Log in administrative user and configure a custom site offline message.
|
||||
$this->drupalLogout();
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalGet('admin/config/development/maintenance');
|
||||
$this->assertNoRaw($admin_message, 'Site maintenance mode message not displayed.');
|
||||
|
||||
$offline_message = 'Sorry, not online.';
|
||||
$edit = [
|
||||
'maintenance_mode_message' => $offline_message,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save configuration'));
|
||||
|
||||
// Logout and verify that custom site offline message is displayed.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('');
|
||||
$this->assertEqual('Site under maintenance', $this->cssSelect('main h1')[0]);
|
||||
$this->assertRaw($offline_message, 'Found the site offline message.');
|
||||
|
||||
// Verify that custom site offline message is not displayed on user/password.
|
||||
$this->drupalGet('user/password');
|
||||
$this->assertText(t('Username or email address'), 'Anonymous users can access user/password');
|
||||
|
||||
// Submit password reset form.
|
||||
$edit = [
|
||||
'name' => $this->user->getUsername(),
|
||||
];
|
||||
$this->drupalPostForm('user/password', $edit, t('Submit'));
|
||||
$mails = $this->drupalGetMails();
|
||||
$start = strpos($mails[0]['body'], 'user/reset/' . $this->user->id());
|
||||
$path = substr($mails[0]['body'], $start, 66 + strlen($this->user->id()));
|
||||
|
||||
// Log in with temporary login link.
|
||||
$this->drupalPostForm($path, [], t('Log in'));
|
||||
$this->assertText($user_message);
|
||||
|
||||
// Regression test to check if title displays in Bartik on maintenance page.
|
||||
\Drupal::service('theme_handler')->install(['bartik']);
|
||||
$this->config('system.theme')->set('default', 'bartik')->save();
|
||||
|
||||
// Logout and verify that offline message is displayed in Bartik.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('');
|
||||
$this->assertEqual('Site under maintenance', $this->cssSelect('main h1')[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responses to non-HTML requests when in maintenance mode.
|
||||
*/
|
||||
public function testNonHtmlRequest() {
|
||||
$this->drupalLogout();
|
||||
\Drupal::state()->set('system.maintenance_mode', TRUE);
|
||||
$formats = ['json', 'xml', 'non-existing'];
|
||||
foreach ($formats as $format) {
|
||||
$this->pass('Testing format ' . $format);
|
||||
$this->drupalGet('<front>', ['query' => ['_format' => $format]]);
|
||||
$this->assertResponse(503);
|
||||
$this->assertRaw('Drupal is currently under maintenance. We should be back shortly. Thank you for your patience.');
|
||||
$this->assertHeader('Content-Type', 'text/plain; charset=UTF-8');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Drupal\system\Tests\System;
|
||||
|
||||
@trigger_error('\Drupal\system\Tests\System\SystemConfigFormTestBase is deprecated in Drupal 8.6.0 and will be removed before Drupal 9.0.0. Use \Drupal\KernelTests\ConfigFormTestBase instead.', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
@@ -10,12 +12,17 @@ use Drupal\simpletest\WebTestBase;
|
||||
*
|
||||
* @see UserAdminSettingsFormTest
|
||||
* For a full working implementation.
|
||||
*
|
||||
* @deprecated in Drupal 8.6.x and will be removed before Drupal 9.0.0. Use
|
||||
* \Drupal\KernelTests\ConfigFormTestBase instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2941907
|
||||
*/
|
||||
abstract class SystemConfigFormTestBase extends WebTestBase {
|
||||
/**
|
||||
* Form ID to use for testing.
|
||||
*
|
||||
* @var \Drupal\Core\Form\FormInterface.
|
||||
* @var \Drupal\Core\Form\FormInterface
|
||||
*/
|
||||
protected $form;
|
||||
|
||||
|
||||
@@ -1,431 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\system\Tests\System;
|
||||
|
||||
use Drupal\Core\StreamWrapper\PublicStream;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests the theme interface functionality by enabling and switching themes, and
|
||||
* using an administration theme.
|
||||
*
|
||||
* @group system
|
||||
*/
|
||||
class ThemeTest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* A user with administrative permissions.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'block', 'file'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
|
||||
|
||||
$this->adminUser = $this->drupalCreateUser(['access administration pages', 'view the administration theme', 'administer themes', 'bypass node access', 'administer blocks']);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->node = $this->drupalCreateNode();
|
||||
$this->drupalPlaceBlock('local_tasks_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the theme settings form.
|
||||
*/
|
||||
public function testThemeSettings() {
|
||||
// Ensure invalid theme settings form URLs return a proper 404.
|
||||
$this->drupalGet('admin/appearance/settings/bartik');
|
||||
$this->assertResponse(404, 'The theme settings form URL for a uninstalled theme could not be found.');
|
||||
$this->drupalGet('admin/appearance/settings/' . $this->randomMachineName());
|
||||
$this->assertResponse(404, 'The theme settings form URL for a non-existent theme could not be found.');
|
||||
$this->assertTrue(\Drupal::service('theme_installer')->install(['stable']));
|
||||
$this->drupalGet('admin/appearance/settings/stable');
|
||||
$this->assertResponse(404, 'The theme settings form URL for a hidden theme is unavailable.');
|
||||
|
||||
// Specify a filesystem path to be used for the logo.
|
||||
$file = current($this->drupalGetTestFiles('image'));
|
||||
$file_relative = strtr($file->uri, ['public:/' => PublicStream::basePath()]);
|
||||
$default_theme_path = 'core/themes/classy';
|
||||
|
||||
$supported_paths = [
|
||||
// Raw stream wrapper URI.
|
||||
$file->uri => [
|
||||
'form' => file_uri_target($file->uri),
|
||||
'src' => file_url_transform_relative(file_create_url($file->uri)),
|
||||
],
|
||||
// Relative path within the public filesystem.
|
||||
file_uri_target($file->uri) => [
|
||||
'form' => file_uri_target($file->uri),
|
||||
'src' => file_url_transform_relative(file_create_url($file->uri)),
|
||||
],
|
||||
// Relative path to a public file.
|
||||
$file_relative => [
|
||||
'form' => $file_relative,
|
||||
'src' => file_url_transform_relative(file_create_url($file->uri)),
|
||||
],
|
||||
// Relative path to an arbitrary file.
|
||||
'core/misc/druplicon.png' => [
|
||||
'form' => 'core/misc/druplicon.png',
|
||||
'src' => base_path() . 'core/misc/druplicon.png',
|
||||
],
|
||||
// Relative path to a file in a theme.
|
||||
$default_theme_path . '/logo.svg' => [
|
||||
'form' => $default_theme_path . '/logo.svg',
|
||||
'src' => base_path() . $default_theme_path . '/logo.svg',
|
||||
],
|
||||
];
|
||||
foreach ($supported_paths as $input => $expected) {
|
||||
$edit = [
|
||||
'default_logo' => FALSE,
|
||||
'logo_path' => $input,
|
||||
];
|
||||
$this->drupalPostForm('admin/appearance/settings', $edit, t('Save configuration'));
|
||||
$this->assertNoText('The custom logo path is invalid.');
|
||||
$this->assertFieldByName('logo_path', $expected['form']);
|
||||
|
||||
// Verify logo path examples.
|
||||
$elements = $this->xpath('//div[contains(@class, :item)]/div[@class=:description]/code', [
|
||||
':item' => 'js-form-item-logo-path',
|
||||
':description' => 'description',
|
||||
]);
|
||||
// Expected default values (if all else fails).
|
||||
$implicit_public_file = 'logo.svg';
|
||||
$explicit_file = 'public://logo.svg';
|
||||
$local_file = $default_theme_path . '/logo.svg';
|
||||
// Adjust for fully qualified stream wrapper URI in public filesystem.
|
||||
if (file_uri_scheme($input) == 'public') {
|
||||
$implicit_public_file = file_uri_target($input);
|
||||
$explicit_file = $input;
|
||||
$local_file = strtr($input, ['public:/' => PublicStream::basePath()]);
|
||||
}
|
||||
// Adjust for fully qualified stream wrapper URI elsewhere.
|
||||
elseif (file_uri_scheme($input) !== FALSE) {
|
||||
$explicit_file = $input;
|
||||
}
|
||||
// Adjust for relative path within public filesystem.
|
||||
elseif ($input == file_uri_target($file->uri)) {
|
||||
$implicit_public_file = $input;
|
||||
$explicit_file = 'public://' . $input;
|
||||
$local_file = PublicStream::basePath() . '/' . $input;
|
||||
}
|
||||
$this->assertEqual((string) $elements[0], $implicit_public_file);
|
||||
$this->assertEqual((string) $elements[1], $explicit_file);
|
||||
$this->assertEqual((string) $elements[2], $local_file);
|
||||
|
||||
// Verify the actual 'src' attribute of the logo being output in a site
|
||||
// branding block.
|
||||
$this->drupalPlaceBlock('system_branding_block', ['region' => 'header']);
|
||||
$this->drupalGet('');
|
||||
$elements = $this->xpath('//header//a[@rel=:rel]/img', [
|
||||
':rel' => 'home',
|
||||
]
|
||||
);
|
||||
$this->assertEqual((string) $elements[0]['src'], $expected['src']);
|
||||
}
|
||||
$unsupported_paths = [
|
||||
// Stream wrapper URI to non-existing file.
|
||||
'public://whatever.png',
|
||||
'private://whatever.png',
|
||||
'temporary://whatever.png',
|
||||
// Bogus stream wrapper URIs.
|
||||
'public:/whatever.png',
|
||||
'://whatever.png',
|
||||
':whatever.png',
|
||||
'public://',
|
||||
// Relative path within the public filesystem to non-existing file.
|
||||
'whatever.png',
|
||||
// Relative path to non-existing file in public filesystem.
|
||||
PublicStream::basePath() . '/whatever.png',
|
||||
// Semi-absolute path to non-existing file in public filesystem.
|
||||
'/' . PublicStream::basePath() . '/whatever.png',
|
||||
// Relative path to arbitrary non-existing file.
|
||||
'core/misc/whatever.png',
|
||||
// Semi-absolute path to arbitrary non-existing file.
|
||||
'/core/misc/whatever.png',
|
||||
// Absolute paths to any local file (even if it exists).
|
||||
\Drupal::service('file_system')->realpath($file->uri),
|
||||
];
|
||||
$this->drupalGet('admin/appearance/settings');
|
||||
foreach ($unsupported_paths as $path) {
|
||||
$edit = [
|
||||
'default_logo' => FALSE,
|
||||
'logo_path' => $path,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save configuration'));
|
||||
$this->assertText('The custom logo path is invalid.');
|
||||
}
|
||||
|
||||
// Upload a file to use for the logo.
|
||||
$edit = [
|
||||
'default_logo' => FALSE,
|
||||
'logo_path' => '',
|
||||
'files[logo_upload]' => \Drupal::service('file_system')->realpath($file->uri),
|
||||
];
|
||||
$this->drupalPostForm('admin/appearance/settings', $edit, t('Save configuration'));
|
||||
|
||||
$fields = $this->xpath($this->constructFieldXpath('name', 'logo_path'));
|
||||
$uploaded_filename = 'public://' . $fields[0]['value'];
|
||||
|
||||
$this->drupalPlaceBlock('system_branding_block', ['region' => 'header']);
|
||||
$this->drupalGet('');
|
||||
$elements = $this->xpath('//header//a[@rel=:rel]/img', [
|
||||
':rel' => 'home',
|
||||
]
|
||||
);
|
||||
$this->assertEqual($elements[0]['src'], file_url_transform_relative(file_create_url($uploaded_filename)));
|
||||
|
||||
$this->container->get('theme_handler')->install(['bartik']);
|
||||
|
||||
// Ensure only valid themes are listed in the local tasks.
|
||||
$this->drupalPlaceBlock('local_tasks_block', ['region' => 'header']);
|
||||
$this->drupalGet('admin/appearance/settings');
|
||||
$theme_handler = \Drupal::service('theme_handler');
|
||||
$this->assertLink($theme_handler->getName('classy'));
|
||||
$this->assertLink($theme_handler->getName('bartik'));
|
||||
$this->assertNoLink($theme_handler->getName('stable'));
|
||||
|
||||
// If a hidden theme is an admin theme it should be viewable.
|
||||
\Drupal::configFactory()->getEditable('system.theme')->set('admin', 'stable')->save();
|
||||
\Drupal::service('router.builder')->rebuildIfNeeded();
|
||||
$this->drupalPlaceBlock('local_tasks_block', ['region' => 'header', 'theme' => 'stable']);
|
||||
$this->drupalGet('admin/appearance/settings');
|
||||
$this->assertLink($theme_handler->getName('stable'));
|
||||
$this->drupalGet('admin/appearance/settings/stable');
|
||||
$this->assertResponse(200, 'The theme settings form URL for a hidden theme that is the admin theme is available.');
|
||||
|
||||
// Ensure default logo and favicons are not triggering custom path
|
||||
// validation errors if their custom paths are set on the form.
|
||||
$edit = [
|
||||
'default_logo' => TRUE,
|
||||
'logo_path' => 'public://whatever.png',
|
||||
'default_favicon' => TRUE,
|
||||
'favicon_path' => 'public://whatever.ico',
|
||||
];
|
||||
$this->drupalPostForm('admin/appearance/settings', $edit, 'Save configuration');
|
||||
$this->assertNoText('The custom logo path is invalid.');
|
||||
$this->assertNoText('The custom favicon path is invalid.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the theme settings logo form.
|
||||
*/
|
||||
public function testThemeSettingsLogo() {
|
||||
// Visit Bartik's theme settings page to replace the logo.
|
||||
$this->container->get('theme_handler')->install(['bartik']);
|
||||
$this->drupalGet('admin/appearance/settings/bartik');
|
||||
$edit = [
|
||||
'default_logo' => FALSE,
|
||||
'logo_path' => 'core/misc/druplicon.png',
|
||||
];
|
||||
$this->drupalPostForm('admin/appearance/settings/bartik', $edit, t('Save configuration'));
|
||||
$this->assertFieldByName('default_logo', FALSE);
|
||||
$this->assertFieldByName('logo_path', 'core/misc/druplicon.png');
|
||||
|
||||
// Make sure the logo and favicon settings are not available when the file
|
||||
// module is not enabled.
|
||||
\Drupal::service('module_installer')->uninstall(['file']);
|
||||
$this->drupalGet('admin/appearance/settings');
|
||||
$this->assertNoText('Logo image settings');
|
||||
$this->assertNoText('Shortcut icon settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the administration theme functionality.
|
||||
*/
|
||||
public function testAdministrationTheme() {
|
||||
$this->container->get('theme_handler')->install(['seven']);
|
||||
|
||||
// Install an administration theme and show it on the node admin pages.
|
||||
$edit = [
|
||||
'admin_theme' => 'seven',
|
||||
'use_admin_theme' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm('admin/appearance', $edit, t('Save configuration'));
|
||||
|
||||
$this->drupalGet('admin/config');
|
||||
$this->assertRaw('core/themes/seven', 'Administration theme used on an administration page.');
|
||||
|
||||
$this->drupalGet('node/' . $this->node->id());
|
||||
$this->assertRaw('core/themes/classy', 'Site default theme used on node page.');
|
||||
|
||||
$this->drupalGet('node/add');
|
||||
$this->assertRaw('core/themes/seven', 'Administration theme used on the add content page.');
|
||||
|
||||
$this->drupalGet('node/' . $this->node->id() . '/edit');
|
||||
$this->assertRaw('core/themes/seven', 'Administration theme used on the edit content page.');
|
||||
|
||||
// Disable the admin theme on the node admin pages.
|
||||
$edit = [
|
||||
'use_admin_theme' => FALSE,
|
||||
];
|
||||
$this->drupalPostForm('admin/appearance', $edit, t('Save configuration'));
|
||||
|
||||
$this->drupalGet('admin/config');
|
||||
$this->assertRaw('core/themes/seven', 'Administration theme used on an administration page.');
|
||||
|
||||
// Ensure that the admin theme is also visible on the 403 page.
|
||||
$normal_user = $this->drupalCreateUser(['view the administration theme']);
|
||||
$this->drupalLogin($normal_user);
|
||||
$this->drupalGet('admin/config');
|
||||
$this->assertResponse(403);
|
||||
$this->assertRaw('core/themes/seven', 'Administration theme used on an administration page.');
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
$this->drupalGet('node/add');
|
||||
$this->assertRaw('core/themes/classy', 'Site default theme used on the add content page.');
|
||||
|
||||
// Reset to the default theme settings.
|
||||
$edit = [
|
||||
'admin_theme' => '0',
|
||||
'use_admin_theme' => FALSE,
|
||||
];
|
||||
$this->drupalPostForm('admin/appearance', $edit, t('Save configuration'));
|
||||
|
||||
$this->drupalGet('admin');
|
||||
$this->assertRaw('core/themes/classy', 'Site default theme used on administration page.');
|
||||
|
||||
$this->drupalGet('node/add');
|
||||
$this->assertRaw('core/themes/classy', 'Site default theme used on the add content page.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test switching the default theme.
|
||||
*/
|
||||
public function testSwitchDefaultTheme() {
|
||||
/** @var \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler */
|
||||
$theme_handler = \Drupal::service('theme_handler');
|
||||
// First, install Stark and set it as the default theme programmatically.
|
||||
$theme_handler->install(['stark']);
|
||||
$this->config('system.theme')->set('default', 'stark')->save();
|
||||
|
||||
// Install Bartik and set it as the default theme.
|
||||
$theme_handler->install(['bartik']);
|
||||
$this->drupalGet('admin/appearance');
|
||||
$this->clickLink(t('Set as default'));
|
||||
$this->assertEqual($this->config('system.theme')->get('default'), 'bartik');
|
||||
|
||||
// Test the default theme on the secondary links (blocks admin page).
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->assertText('Bartik(' . t('active tab') . ')', 'Default local task on blocks admin page is the default theme.');
|
||||
// Switch back to Stark and test again to test that the menu cache is cleared.
|
||||
$this->drupalGet('admin/appearance');
|
||||
// Stark is the first 'Set as default' link.
|
||||
$this->clickLink(t('Set as default'));
|
||||
$this->drupalGet('admin/structure/block');
|
||||
$this->assertText('Stark(' . t('active tab') . ')', 'Default local task on blocks admin page has changed.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test themes can't be installed when the base theme or engine is missing.
|
||||
*
|
||||
* Include test for themes that have a missing base theme somewhere further up
|
||||
* the chain than the immediate base theme.
|
||||
*/
|
||||
public function testInvalidTheme() {
|
||||
// theme_page_test_system_info_alter() un-hides all hidden themes.
|
||||
$this->container->get('module_installer')->install(['theme_page_test']);
|
||||
// Clear the system_list() and theme listing cache to pick up the change.
|
||||
$this->container->get('theme_handler')->reset();
|
||||
$this->drupalGet('admin/appearance');
|
||||
$this->assertText(t('This theme requires the base theme @base_theme to operate correctly.', ['@base_theme' => 'not_real_test_basetheme']));
|
||||
$this->assertText(t('This theme requires the base theme @base_theme to operate correctly.', ['@base_theme' => 'test_invalid_basetheme']));
|
||||
$this->assertText(t('This theme requires the theme engine @theme_engine to operate correctly.', ['@theme_engine' => 'not_real_engine']));
|
||||
// Check for the error text of a theme with the wrong core version.
|
||||
$this->assertText("This theme is not compatible with Drupal 8.x. Check that the .info.yml file contains the correct 'core' value.");
|
||||
// Check for the error text of a theme without a content region.
|
||||
$this->assertText("This theme is missing a 'content' region.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test uninstalling of themes works.
|
||||
*/
|
||||
public function testUninstallingThemes() {
|
||||
// Install Bartik and set it as the default theme.
|
||||
\Drupal::service('theme_handler')->install(['bartik']);
|
||||
// Set up seven as the admin theme.
|
||||
\Drupal::service('theme_handler')->install(['seven']);
|
||||
$edit = [
|
||||
'admin_theme' => 'seven',
|
||||
'use_admin_theme' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm('admin/appearance', $edit, t('Save configuration'));
|
||||
$this->drupalGet('admin/appearance');
|
||||
$this->clickLink(t('Set as default'));
|
||||
|
||||
// Check that seven cannot be uninstalled as it is the admin theme.
|
||||
$this->assertNoRaw('Uninstall Seven theme', 'A link to uninstall the Seven theme does not appear on the theme settings page.');
|
||||
// Check that bartik cannot be uninstalled as it is the default theme.
|
||||
$this->assertNoRaw('Uninstall Bartik theme', 'A link to uninstall the Bartik theme does not appear on the theme settings page.');
|
||||
// Check that the classy theme cannot be uninstalled as it is a base theme
|
||||
// of seven and bartik.
|
||||
$this->assertNoRaw('Uninstall Classy theme', 'A link to uninstall the Classy theme does not appear on the theme settings page.');
|
||||
|
||||
// Install Stark and set it as the default theme.
|
||||
\Drupal::service('theme_handler')->install(['stark']);
|
||||
|
||||
$edit = [
|
||||
'admin_theme' => 'stark',
|
||||
'use_admin_theme' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm('admin/appearance', $edit, t('Save configuration'));
|
||||
|
||||
// Check that seven can be uninstalled now.
|
||||
$this->assertRaw('Uninstall Seven theme', 'A link to uninstall the Seven theme does appear on the theme settings page.');
|
||||
// Check that the classy theme still cannot be uninstalled as it is a
|
||||
// base theme of bartik.
|
||||
$this->assertNoRaw('Uninstall Classy theme', 'A link to uninstall the Classy theme does not appear on the theme settings page.');
|
||||
|
||||
// Change the default theme to stark, stark is second in the list.
|
||||
$this->clickLink(t('Set as default'), 1);
|
||||
|
||||
// Check that bartik can be uninstalled now.
|
||||
$this->assertRaw('Uninstall Bartik theme', 'A link to uninstall the Bartik theme does appear on the theme settings page.');
|
||||
|
||||
// Check that the classy theme still can't be uninstalled as neither of its
|
||||
// base themes have been.
|
||||
$this->assertNoRaw('Uninstall Classy theme', 'A link to uninstall the Classy theme does not appear on the theme settings page.');
|
||||
|
||||
// Uninstall each of the three themes starting with Bartik.
|
||||
$this->clickLink(t('Uninstall'));
|
||||
$this->assertRaw('The <em class="placeholder">Bartik</em> theme has been uninstalled');
|
||||
// Seven is the second in the list.
|
||||
$this->clickLink(t('Uninstall'));
|
||||
$this->assertRaw('The <em class="placeholder">Seven</em> theme has been uninstalled');
|
||||
|
||||
// Check that the classy theme still can't be uninstalled as it is hidden.
|
||||
$this->assertNoRaw('Uninstall Classy theme', 'A link to uninstall the Classy theme does not appear on the theme settings page.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests installing a theme and setting it as default.
|
||||
*/
|
||||
public function testInstallAndSetAsDefault() {
|
||||
$this->drupalGet('admin/appearance');
|
||||
// Bartik is uninstalled in the test profile and has the third "Install and
|
||||
// set as default" link.
|
||||
$this->clickLink(t('Install and set as default'), 2);
|
||||
// Test the confirmation message.
|
||||
$this->assertText('Bartik is now the default theme.');
|
||||
// Make sure Bartik is now set as the default theme in config.
|
||||
$this->assertEqual($this->config('system.theme')->get('default'), 'bartik');
|
||||
|
||||
// This checks for a regression. See https://www.drupal.org/node/2498691.
|
||||
$this->assertNoText('The bartik theme was not found.');
|
||||
|
||||
$themes = \Drupal::service('theme_handler')->rebuildThemeData();
|
||||
$version = $themes['bartik']->info['version'];
|
||||
|
||||
// Confirm Bartik is indicated as the default theme.
|
||||
$this->assertTextPattern('/Bartik ' . preg_quote($version) . '\s{2,}\(default theme\)/');
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user