Issue #3294914 by Spokje, quietone, bbrala, longwave, Gábor Hojtsy, benjifisher, dww, xjm, rkoller: Create dedicated error section for missing removed core modules/themes on update
parent
7643161492
commit
22a56817e0
|
@ -28,6 +28,30 @@ use Drupal\Core\Url;
|
|||
use GuzzleHttp\Exception\TransferException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
// cspell:ignore quickedit
|
||||
|
||||
/**
|
||||
* An array of machine names of modules that were removed from Drupal core.
|
||||
*/
|
||||
const DRUPAL_CORE_REMOVED_MODULE_LIST = [
|
||||
'aggregator' => 'Aggregator',
|
||||
'ckeditor' => 'CKEditor',
|
||||
'color' => 'Color',
|
||||
'hal' => 'HAL',
|
||||
'quickedit' => 'Quick Edit',
|
||||
'rdf' => 'RDF',
|
||||
];
|
||||
|
||||
/**
|
||||
* An array of machine names of themes that were removed from Drupal core.
|
||||
*/
|
||||
const DRUPAL_CORE_REMOVED_THEME_LIST = [
|
||||
'bartik' => 'Bartik',
|
||||
'classy' => 'Classy',
|
||||
'seven' => 'Seven',
|
||||
'stable' => 'Stable',
|
||||
];
|
||||
|
||||
/**
|
||||
* Implements hook_requirements().
|
||||
*/
|
||||
|
@ -989,13 +1013,16 @@ function system_requirements($phase) {
|
|||
|
||||
// Display an error if a newly introduced dependency in a module is not resolved.
|
||||
if ($phase === 'update' || $phase === 'runtime') {
|
||||
$create_extension_incompatibility_list = function ($extension_names, $description, $title) {
|
||||
$create_extension_incompatibility_list = function (array $extension_names, PluralTranslatableMarkup $description, PluralTranslatableMarkup $title, TranslatableMarkup|string $message = '', TranslatableMarkup|string $additional_description = '') {
|
||||
if ($message === '') {
|
||||
$message = new TranslatableMarkup('Review the <a href=":url"> suggestions for resolving this incompatibility</a> to repair your installation, and then re-run update.php.', [':url' => 'https://www.drupal.org/docs/updating-drupal/troubleshooting-database-updates']);
|
||||
}
|
||||
// Use an inline twig template to:
|
||||
// - Concatenate two MarkupInterface objects and preserve safeness.
|
||||
// - Concatenate MarkupInterface objects and preserve safeness.
|
||||
// - Use the item_list theme for the extension list.
|
||||
$template = [
|
||||
'#type' => 'inline_template',
|
||||
'#template' => '{{ description }}{{ extensions }}',
|
||||
'#template' => '{{ description }}{{ extensions }}{{ additional_description }}<br>',
|
||||
'#context' => [
|
||||
'extensions' => [
|
||||
'#theme' => 'item_list',
|
||||
|
@ -1004,15 +1031,13 @@ function system_requirements($phase) {
|
|||
];
|
||||
$template['#context']['extensions']['#items'] = $extension_names;
|
||||
$template['#context']['description'] = $description;
|
||||
$template['#context']['additional_description'] = $additional_description;
|
||||
return [
|
||||
'title' => $title,
|
||||
'value' => [
|
||||
'list' => $template,
|
||||
'handbook_link' => [
|
||||
'#markup' => t(
|
||||
'Review the <a href=":url"> suggestions for resolving this incompatibility</a> to repair your installation, and then re-run update.php.',
|
||||
[':url' => 'https://www.drupal.org/docs/8/update/troubleshooting-database-updates']
|
||||
),
|
||||
'#markup' => $message,
|
||||
],
|
||||
],
|
||||
'severity' => REQUIREMENT_ERROR,
|
||||
|
@ -1134,13 +1159,89 @@ function system_requirements($phase) {
|
|||
);
|
||||
}
|
||||
|
||||
// Look for invalid modules.
|
||||
$extension_config = \Drupal::configFactory()->get('core.extension');
|
||||
$is_missing_extension = function ($extension_name) use (&$module_extension_list) {
|
||||
return !$module_extension_list->exists($extension_name);
|
||||
};
|
||||
|
||||
$invalid_modules = array_filter(array_keys($extension_config->get('module')), $is_missing_extension);
|
||||
// Look for removed core modules.
|
||||
$is_removed_module = function ($extension_name) use ($module_extension_list) {
|
||||
return !$module_extension_list->exists($extension_name)
|
||||
&& array_key_exists($extension_name, DRUPAL_CORE_REMOVED_MODULE_LIST);
|
||||
};
|
||||
$removed_modules = array_filter(array_keys($extension_config->get('module')), $is_removed_module);
|
||||
if (!empty($removed_modules)) {
|
||||
$list = [];
|
||||
foreach ($removed_modules as $removed_module) {
|
||||
$list[] = t('<a href=":url">@module</a>', [
|
||||
':url' => "https://www.drupal.org/project/$removed_module",
|
||||
'@module' => DRUPAL_CORE_REMOVED_MODULE_LIST[$removed_module],
|
||||
]);
|
||||
}
|
||||
$requirements['removed_module'] = $create_extension_incompatibility_list(
|
||||
$list,
|
||||
new PluralTranslatableMarkup(
|
||||
count($removed_modules),
|
||||
'You must add the following contributed module and reload this page.',
|
||||
'You must add the following contributed modules and reload this page.'
|
||||
),
|
||||
new PluralTranslatableMarkup(
|
||||
count($removed_modules),
|
||||
'Removed core module',
|
||||
'Removed core modules'
|
||||
),
|
||||
new TranslatableMarkup(
|
||||
'For more information read the <a href=":url">documentation on deprecated modules.</a>',
|
||||
[':url' => 'https://www.drupal.org/node/3223395#s-recommendations-for-deprecated-modules']
|
||||
),
|
||||
new PluralTranslatableMarkup(
|
||||
count($removed_modules),
|
||||
'This module is installed on your site but is no longer provided by Core.',
|
||||
'These modules are installed on your site but are no longer provided by Core.'
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Look for removed core themes.
|
||||
$is_removed_theme = function ($extension_name) use ($theme_extension_list) {
|
||||
return !$theme_extension_list->exists($extension_name)
|
||||
&& array_key_exists($extension_name, DRUPAL_CORE_REMOVED_THEME_LIST);
|
||||
};
|
||||
$removed_themes = array_filter(array_keys($extension_config->get('theme')), $is_removed_theme);
|
||||
if (!empty($removed_themes)) {
|
||||
$list = [];
|
||||
foreach ($removed_themes as $removed_theme) {
|
||||
$list[] = t('<a href=":url">@theme</a>', [
|
||||
':url' => "https://www.drupal.org/project/$removed_theme",
|
||||
'@theme' => DRUPAL_CORE_REMOVED_THEME_LIST[$removed_theme],
|
||||
]);
|
||||
}
|
||||
$requirements['removed_theme'] = $create_extension_incompatibility_list(
|
||||
$list,
|
||||
new PluralTranslatableMarkup(
|
||||
count($removed_themes),
|
||||
'You must add the following contributed theme and reload this page.',
|
||||
'You must add the following contributed themes and reload this page.'
|
||||
),
|
||||
new PluralTranslatableMarkup(
|
||||
count($removed_themes),
|
||||
'Removed core theme',
|
||||
'Removed core themes'
|
||||
),
|
||||
new TranslatableMarkup(
|
||||
'For more information read the <a href=":url">documentation on deprecated themes.</a>',
|
||||
[':url' => 'https://www.drupal.org/node/3223395#s-recommendations-for-deprecated-themes']
|
||||
),
|
||||
new PluralTranslatableMarkup(
|
||||
count($removed_themes),
|
||||
'This theme is installed on your site but is no longer provided by Core.',
|
||||
'These themes are installed on your site but are no longer provided by Core.'
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Look for missing modules.
|
||||
$is_missing_module = function ($extension_name) use ($module_extension_list) {
|
||||
return !$module_extension_list->exists($extension_name) && !in_array($extension_name, array_keys(DRUPAL_CORE_REMOVED_MODULE_LIST), TRUE);
|
||||
};
|
||||
$invalid_modules = array_filter(array_keys($extension_config->get('module')), $is_missing_module);
|
||||
|
||||
if (!empty($invalid_modules)) {
|
||||
$requirements['invalid_module'] = $create_extension_incompatibility_list(
|
||||
|
@ -1160,7 +1261,7 @@ function system_requirements($phase) {
|
|||
|
||||
// Look for invalid themes.
|
||||
$is_missing_theme = function ($extension_name) use (&$theme_extension_list) {
|
||||
return !$theme_extension_list->exists($extension_name);
|
||||
return !$theme_extension_list->exists($extension_name) && !in_array($extension_name, array_keys(DRUPAL_CORE_REMOVED_THEME_LIST), TRUE);
|
||||
};
|
||||
$invalid_themes = array_filter(array_keys($extension_config->get('theme')), $is_missing_theme);
|
||||
if (!empty($invalid_themes)) {
|
||||
|
|
|
@ -224,7 +224,7 @@ class UpdateScriptTest extends BrowserTestBase {
|
|||
*
|
||||
* @dataProvider providerExtensionCompatibilityChange
|
||||
*/
|
||||
public function testExtensionCompatibilityChange(array $correct_info, array $breaking_info, $expected_error) {
|
||||
public function testExtensionCompatibilityChange(array $correct_info, array $breaking_info, string $expected_error): void {
|
||||
$extension_type = $correct_info['type'];
|
||||
$this->drupalLogin(
|
||||
$this->drupalCreateUser(
|
||||
|
@ -236,8 +236,9 @@ class UpdateScriptTest extends BrowserTestBase {
|
|||
)
|
||||
);
|
||||
|
||||
$extension_machine_name = "changing_extension";
|
||||
$extension_name = "$extension_machine_name name";
|
||||
$extension_machine_names = ['changing_extension'];
|
||||
$extension_name = "$extension_machine_names[0] name";
|
||||
$test_error_urls = ['https://www.drupal.org/docs/updating-drupal/troubleshooting-database-updates'];
|
||||
|
||||
$test_error_text = "Incompatible $extension_type "
|
||||
. $expected_error
|
||||
|
@ -247,25 +248,28 @@ class UpdateScriptTest extends BrowserTestBase {
|
|||
if ($extension_type === 'theme') {
|
||||
$base_info['base theme'] = FALSE;
|
||||
}
|
||||
$folder_path = \Drupal::getContainer()->getParameter('site.path') . "/{$extension_type}s/$extension_machine_name";
|
||||
$file_path = "$folder_path/$extension_machine_name.info.yml";
|
||||
$folder_path = \Drupal::getContainer()->getParameter('site.path') . "/{$extension_type}s/$extension_machine_names[0]";
|
||||
$file_path = "$folder_path/$extension_machine_names[0].info.yml";
|
||||
mkdir($folder_path, 0777, TRUE);
|
||||
file_put_contents($file_path, Yaml::encode($base_info + $correct_info));
|
||||
$this->enableExtension($extension_type, $extension_machine_name, $extension_name);
|
||||
$this->assertInstalledExtensionConfig($extension_type, $extension_machine_name);
|
||||
$this->enableExtensions($extension_type, $extension_machine_names, [$extension_name]);
|
||||
$this->assertInstalledExtensionsConfig($extension_type, $extension_machine_names);
|
||||
|
||||
// If there are no requirements warnings or errors, we expect to be able to
|
||||
// go through the update process uninterrupted.
|
||||
$this->assertUpdateWithNoError($test_error_text, $extension_type, $extension_machine_name);
|
||||
$this->drupalGet($this->statusReportUrl);
|
||||
$this->assertUpdateWithNoErrors([$test_error_text], $extension_type, $extension_machine_names);
|
||||
|
||||
// Change the values in the info.yml and confirm updating is not possible.
|
||||
file_put_contents($file_path, Yaml::encode($base_info + $breaking_info));
|
||||
$this->assertErrorOnUpdate($test_error_text, $extension_type, $extension_machine_name);
|
||||
$this->drupalGet($this->statusReportUrl);
|
||||
$this->assertErrorOnUpdates([$test_error_text], $extension_type, $extension_machine_names, $test_error_urls);
|
||||
|
||||
// Fix the values in the info.yml file and confirm updating is possible
|
||||
// again.
|
||||
file_put_contents($file_path, Yaml::encode($base_info + $correct_info));
|
||||
$this->assertUpdateWithNoError($test_error_text, $extension_type, $extension_machine_name);
|
||||
$this->drupalGet($this->statusReportUrl);
|
||||
$this->assertUpdateWithNoErrors([$test_error_text], $extension_type, $extension_machine_names);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -329,53 +333,165 @@ class UpdateScriptTest extends BrowserTestBase {
|
|||
/**
|
||||
* Tests that a missing extension prevents updates.
|
||||
*
|
||||
* @param string $extension_type
|
||||
* The extension type, either 'module' or 'theme'.
|
||||
* @param array $core
|
||||
* An array keyed by 'module' and 'theme' where each sub array contains
|
||||
* a list of extension machine names.
|
||||
* @param array $contrib
|
||||
* An array keyed by 'module' and 'theme' where each sub array contains
|
||||
* a list of extension machine names.
|
||||
*
|
||||
* @dataProvider providerMissingExtension
|
||||
*/
|
||||
public function testMissingExtension($extension_type) {
|
||||
public function testMissingExtension(array $core, array $contrib): void {
|
||||
$this->drupalLogin(
|
||||
$this->drupalCreateUser(
|
||||
[
|
||||
'administer software updates',
|
||||
'administer site configuration',
|
||||
$extension_type === 'module' ? 'administer modules' : 'administer themes',
|
||||
'administer modules',
|
||||
'administer themes',
|
||||
]
|
||||
)
|
||||
);
|
||||
$extension_machine_name = "disappearing_$extension_type";
|
||||
$extension_name = 'The magically disappearing extension';
|
||||
$test_error_text = "Missing or invalid $extension_type "
|
||||
. "The following $extension_type is marked as installed in the core.extension configuration, but it is missing:"
|
||||
. $extension_machine_name
|
||||
. static::HANDBOOK_MESSAGE;
|
||||
$extension_info = [
|
||||
'name' => $extension_name,
|
||||
'type' => $extension_type,
|
||||
|
||||
$all_extensions_info = [];
|
||||
$file_paths = [];
|
||||
$test_error_texts = [];
|
||||
$test_error_urls = [];
|
||||
$extension_base_info = [
|
||||
'version' => 'VERSION',
|
||||
'core_version_requirement' => '^8 || ^9 || ^10',
|
||||
];
|
||||
if ($extension_type === 'theme') {
|
||||
$extension_info['base theme'] = FALSE;
|
||||
|
||||
// For each core extension create and error of info.yml information and
|
||||
// the expected error message.
|
||||
foreach ($core as $type => $extensions) {
|
||||
$removed_list = [];
|
||||
$error_url = 'https://www.drupal.org/node/3223395#s-recommendations-for-deprecated-modules';
|
||||
$extension_base_info += ['package' => 'Core'];
|
||||
if ($type === 'module') {
|
||||
$removed_core_list = \DRUPAL_CORE_REMOVED_MODULE_LIST;
|
||||
}
|
||||
else {
|
||||
$removed_core_list = \DRUPAL_CORE_REMOVED_THEME_LIST;
|
||||
}
|
||||
|
||||
foreach ($extensions as $extension) {
|
||||
$extension_info = $extension_base_info +
|
||||
[
|
||||
'name' => "The magically disappearing core $type $extension",
|
||||
'type' => $type,
|
||||
];
|
||||
if ($type === 'theme') {
|
||||
$extension_info['base theme'] = FALSE;
|
||||
}
|
||||
$all_extensions_info[$extension] = $extension_info;
|
||||
$removed_list[] = $removed_core_list[$extension];
|
||||
}
|
||||
|
||||
// Create the requirements test message.
|
||||
if (!empty($extensions)) {
|
||||
$handbook_message = "For more information read the documentation on deprecated {$type}s.";
|
||||
if (count($removed_list) === 1) {
|
||||
$test_error_texts[$type][] = "Removed core {$type} "
|
||||
. "You must add the following contributed $type and reload this page."
|
||||
. implode($removed_list)
|
||||
. "This $type is installed on your site but is no longer provided by Core."
|
||||
. $handbook_message;
|
||||
}
|
||||
else {
|
||||
$test_error_texts[$type][] = "Removed core {$type}s "
|
||||
. "You must add the following contributed {$type}s and reload this page."
|
||||
. implode($removed_list)
|
||||
. "These {$type}s are installed on your site but are no longer provided by Core."
|
||||
. $handbook_message;
|
||||
}
|
||||
$test_error_urls[$type][] = $error_url;
|
||||
}
|
||||
}
|
||||
|
||||
// For each contrib extension create and error of info.yml information and
|
||||
// the expected error message.
|
||||
foreach ($contrib as $type => $extensions) {
|
||||
unset($extension_base_info['package']);
|
||||
$handbook_message = 'Review the suggestions for resolving this incompatibility to repair your installation, and then re-run update.php.';
|
||||
$error_url = 'https://www.drupal.org/docs/updating-drupal/troubleshooting-database-updates';
|
||||
foreach ($extensions as $extension) {
|
||||
$extension_info = $extension_base_info +
|
||||
[
|
||||
'name' => "The magically disappearing contrib $type $extension",
|
||||
'type' => $type,
|
||||
];
|
||||
if ($type === 'theme') {
|
||||
$extension_info['base theme'] = FALSE;
|
||||
}
|
||||
$all_extensions_info[$extension] = $extension_info;
|
||||
}
|
||||
|
||||
// Create the requirements test message.
|
||||
if (!empty($extensions)) {
|
||||
if (count($extensions) === 1) {
|
||||
$test_error_texts[$type][] = "Missing or invalid {$type} "
|
||||
. "The following {$type} is marked as installed in the core.extension configuration, but it is missing:"
|
||||
. implode($extensions)
|
||||
. $handbook_message;
|
||||
}
|
||||
else {
|
||||
$test_error_texts[$type][] = "Missing or invalid {$type}s "
|
||||
. "The following {$type}s are marked as installed in the core.extension configuration, but they are missing:"
|
||||
. implode($extensions)
|
||||
. $handbook_message;
|
||||
}
|
||||
$test_error_urls[$type][] = $error_url;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the info.yml files for each extension.
|
||||
foreach ($all_extensions_info as $machine_name => $extension_info) {
|
||||
$type = $extension_info['type'];
|
||||
$folder_path = \Drupal::getContainer()->getParameter('site.path') . "/{$type}s/contrib/$machine_name";
|
||||
$file_path = "$folder_path/$machine_name.info.yml";
|
||||
mkdir($folder_path, 0777, TRUE);
|
||||
file_put_contents($file_path, Yaml::encode($extension_info));
|
||||
$file_paths[$machine_name] = $file_path;
|
||||
}
|
||||
|
||||
// Enable all the extensions.
|
||||
foreach ($all_extensions_info as $machine_name => $extension_info) {
|
||||
$extension_machine_names = [$machine_name];
|
||||
$extension_names = [$extension_info['name']];
|
||||
$this->enableExtensions($extension_info['type'], $extension_machine_names, $extension_names);
|
||||
}
|
||||
$folder_path = \Drupal::getContainer()->getParameter('site.path') . "/{$extension_type}s/$extension_machine_name";
|
||||
$file_path = "$folder_path/$extension_machine_name.info.yml";
|
||||
mkdir($folder_path, 0777, TRUE);
|
||||
file_put_contents($file_path, Yaml::encode($extension_info));
|
||||
$this->enableExtension($extension_type, $extension_machine_name, $extension_name);
|
||||
|
||||
// If there are no requirements warnings or errors, we expect to be able to
|
||||
// go through the update process uninterrupted.
|
||||
$this->assertUpdateWithNoError($test_error_text, $extension_type, $extension_machine_name);
|
||||
$this->drupalGet($this->statusReportUrl);
|
||||
$types = ['module', 'theme'];
|
||||
foreach ($types as $type) {
|
||||
$all = array_merge($core[$type], $contrib[$type]);
|
||||
$this->assertUpdateWithNoErrors($test_error_texts[$type], $type, $all);
|
||||
}
|
||||
|
||||
// Delete the info.yml and confirm updates are prevented.
|
||||
unlink($file_path);
|
||||
$this->assertErrorOnUpdate($test_error_text, $extension_type, $extension_machine_name);
|
||||
// Delete the info.yml(s) and confirm updates are prevented.
|
||||
foreach ($file_paths as $file_path) {
|
||||
unlink($file_path);
|
||||
}
|
||||
$this->drupalGet($this->statusReportUrl);
|
||||
foreach ($types as $type) {
|
||||
$all = array_merge($core[$type], $contrib[$type]);
|
||||
$this->assertErrorOnUpdates($test_error_texts[$type], $type, $all, $test_error_urls[$type]);
|
||||
}
|
||||
|
||||
// Add the info.yml file back and confirm we are able to go through the
|
||||
// Add the info.yml file(s) back and confirm we are able to go through the
|
||||
// update process uninterrupted.
|
||||
file_put_contents($file_path, Yaml::encode($extension_info));
|
||||
$this->assertUpdateWithNoError($test_error_text, $extension_type, $extension_machine_name);
|
||||
foreach ($all_extensions_info as $machine_name => $extension_info) {
|
||||
file_put_contents($file_paths[$machine_name], Yaml::encode($extension_info));
|
||||
}
|
||||
$this->drupalGet($this->statusReportUrl);
|
||||
foreach ($types as $type) {
|
||||
$all = array_merge($core[$type], $contrib[$type]);
|
||||
$this->assertUpdateWithNoErrors($test_error_texts[$type], $type, $all);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -427,12 +543,44 @@ class UpdateScriptTest extends BrowserTestBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Data provider for testMissingExtension().
|
||||
* Data provider for ::testMissingExtension().
|
||||
*
|
||||
* @return array[]
|
||||
* Set of testcases to pass to the test method.
|
||||
*/
|
||||
public function providerMissingExtension() {
|
||||
public function providerMissingExtension(): array {
|
||||
return [
|
||||
'module' => ['module'],
|
||||
'theme' => ['theme'],
|
||||
'core only' => [
|
||||
'core' => [
|
||||
'module' => ['aggregator'],
|
||||
'theme' => ['seven'],
|
||||
],
|
||||
'contrib' => [
|
||||
'module' => [],
|
||||
'theme' => [],
|
||||
],
|
||||
],
|
||||
'contrib only' => [
|
||||
'core' => [
|
||||
'module' => [],
|
||||
'theme' => [],
|
||||
],
|
||||
'contrib' => [
|
||||
'module' => ['module'],
|
||||
'theme' => ['theme'],
|
||||
],
|
||||
],
|
||||
'core and contrib' =>
|
||||
[
|
||||
'core' => [
|
||||
'module' => ['aggregator', 'rdf'],
|
||||
'theme' => ['seven'],
|
||||
],
|
||||
'contrib' => [
|
||||
'module' => ['module_a', 'module_b'],
|
||||
'theme' => ['theme_a', 'theme_b'],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -441,22 +589,55 @@ class UpdateScriptTest extends BrowserTestBase {
|
|||
*
|
||||
* @param string $extension_type
|
||||
* The extension type.
|
||||
* @param string $extension_machine_name
|
||||
* The extension machine name.
|
||||
* @param string $extension_name
|
||||
* The extension name.
|
||||
* @param array $extension_machine_names
|
||||
* An array of the extension machine names.
|
||||
* @param array $extension_names
|
||||
* An array of extension names.
|
||||
*/
|
||||
protected function enableExtension($extension_type, $extension_machine_name, $extension_name) {
|
||||
protected function enableExtensions(string $extension_type, array $extension_machine_names, array $extension_names): void {
|
||||
if ($extension_type === 'module') {
|
||||
$edit = [
|
||||
"modules[$extension_machine_name][enable]" => $extension_machine_name,
|
||||
];
|
||||
$edit = [];
|
||||
foreach ($extension_machine_names as $extension_machine_name) {
|
||||
$edit["modules[$extension_machine_name][enable]"] = $extension_machine_name;
|
||||
}
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
}
|
||||
elseif ($extension_type === 'theme') {
|
||||
$this->drupalGet('admin/appearance');
|
||||
$this->click("a[title~=\"$extension_name\"]");
|
||||
foreach ($extension_names as $extension_name) {
|
||||
$this->click("a[title~=\"$extension_name\"]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables extensions the UI.
|
||||
*
|
||||
* @param array $extension_info
|
||||
* An array of extension information arrays. The array is keyed by 'module'
|
||||
* and 'theme'.
|
||||
*/
|
||||
protected function enableMissingExtensions(array $extension_info): void {
|
||||
$edit = [];
|
||||
foreach ($extension_info as $info) {
|
||||
if ($info['type'] === 'module') {
|
||||
$machine_name = $info['machine_name'];
|
||||
$edit["modules[$machine_name][enable]"] = $machine_name;
|
||||
}
|
||||
if (!empty($edit)) {
|
||||
$this->drupalGet('admin/modules');
|
||||
$this->submitForm($edit, 'Install');
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($extension_info['theme'])) {
|
||||
$this->drupalGet('admin/appearance');
|
||||
foreach ($extension_info as $info) {
|
||||
if ($info['type' === 'theme']) {
|
||||
$this->click('a[title~="' . $info['name'] . '"]');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -779,70 +960,83 @@ class UpdateScriptTest extends BrowserTestBase {
|
|||
*
|
||||
* @param string $extension_type
|
||||
* The extension type, either 'module' or 'theme'.
|
||||
* @param string $extension_machine_name
|
||||
* The extension machine name.
|
||||
* @param array $extension_machine_names
|
||||
* An array of the extension machine names.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertInstalledExtensionConfig(string $extension_type, string $extension_machine_name): void {
|
||||
protected function assertInstalledExtensionsConfig(string $extension_type, array $extension_machine_names): void {
|
||||
$extension_config = $this->container->get('config.factory')->getEditable('core.extension');
|
||||
$this->assertSame(0, $extension_config->get("$extension_type.$extension_machine_name"));
|
||||
foreach ($extension_machine_names as $extension_machine_name) {
|
||||
$this->assertSame(0, $extension_config->get("$extension_type.$extension_machine_name"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts a particular error is not shown on update and status report pages.
|
||||
* Asserts particular errors are not shown on update and status report pages.
|
||||
*
|
||||
* @param string $unexpected_error_text
|
||||
* The error text that should not be shown.
|
||||
* @param array $unexpected_error_texts
|
||||
* An array of the error texts that should not be shown.
|
||||
* @param string $extension_type
|
||||
* The extension type, either 'module' or 'theme'.
|
||||
* @param string $extension_machine_name
|
||||
* The extension machine name.
|
||||
* @param array $extension_machine_names
|
||||
* An array of the extension machine names.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ResponseTextException
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertUpdateWithNoError(string $unexpected_error_text, string $extension_type, string $extension_machine_name): void {
|
||||
protected function assertUpdateWithNoErrors(array $unexpected_error_texts, string $extension_type, array $extension_machine_names): void {
|
||||
$assert_session = $this->assertSession();
|
||||
$this->drupalGet($this->statusReportUrl);
|
||||
$this->assertSession()->pageTextNotContains($unexpected_error_text);
|
||||
foreach ($unexpected_error_texts as $unexpected_error_text) {
|
||||
$this->assertSession()->pageTextNotContains($unexpected_error_text);
|
||||
}
|
||||
$this->drupalGet($this->updateUrl, ['external' => TRUE]);
|
||||
$this->assertSession()->pageTextNotContains($unexpected_error_text);
|
||||
foreach ($unexpected_error_texts as $unexpected_error_text) {
|
||||
$this->assertSession()->pageTextNotContains($unexpected_error_text);
|
||||
}
|
||||
$this->updateRequirementsProblem();
|
||||
$this->clickLink('Continue');
|
||||
$assert_session->pageTextContains('No pending updates.');
|
||||
$this->assertInstalledExtensionConfig($extension_type, $extension_machine_name);
|
||||
$this->assertInstalledExtensionsConfig($extension_type, $extension_machine_names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts an error is shown on the update and status report pages.
|
||||
* Asserts errors are shown on the update and status report pages.
|
||||
*
|
||||
* @param string $expected_error_text
|
||||
* The expected error text.
|
||||
* @param array $expected_error_texts
|
||||
* The expected error texts.
|
||||
* @param string $extension_type
|
||||
* The extension type, either 'module' or 'theme'.
|
||||
* @param string $extension_machine_name
|
||||
* The extension machine name.
|
||||
* @param array $extension_machine_names
|
||||
* The extension machine names.
|
||||
* @param array $test_error_urls
|
||||
* The URLs in the error texts.
|
||||
*
|
||||
* @throws \Behat\Mink\Exception\ExpectationException
|
||||
* @throws \Behat\Mink\Exception\ResponseTextException
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertErrorOnUpdate(string $expected_error_text, string $extension_type, string $extension_machine_name): void {
|
||||
protected function assertErrorOnUpdates(array $expected_error_texts, string $extension_type, array $extension_machine_names, array $test_error_urls): void {
|
||||
$assert_session = $this->assertSession();
|
||||
$this->drupalGet($this->statusReportUrl);
|
||||
$this->assertSession()->pageTextContains($expected_error_text);
|
||||
foreach ($expected_error_texts as $expected_error_text) {
|
||||
$this->assertSession()->pageTextContains($expected_error_text);
|
||||
}
|
||||
foreach ($test_error_urls as $test_error_url) {
|
||||
$this->assertSession()->linkByHrefExists($test_error_url);
|
||||
}
|
||||
|
||||
// Reload the update page to ensure the extension with the breaking values
|
||||
// has not been uninstalled or otherwise affected.
|
||||
for ($reload = 0; $reload <= 1; $reload++) {
|
||||
$this->drupalGet($this->updateUrl, ['external' => TRUE]);
|
||||
$this->assertSession()->pageTextContains($expected_error_text);
|
||||
foreach ($expected_error_texts as $expected_error_text) {
|
||||
$this->assertSession()->pageTextContains($expected_error_text);
|
||||
}
|
||||
$assert_session->linkNotExists('Continue');
|
||||
}
|
||||
$this->assertInstalledExtensionConfig($extension_type, $extension_machine_name);
|
||||
$this->assertInstalledExtensionsConfig($extension_type, $extension_machine_names);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue