diff --git a/core/modules/system/src/Controller/SystemController.php b/core/modules/system/src/Controller/SystemController.php index c848221dd2..578a8c743f 100644 --- a/core/modules/system/src/Controller/SystemController.php +++ b/core/modules/system/src/Controller/SystemController.php @@ -87,7 +87,7 @@ public function __construct(SystemManager $systemManager, ThemeAccessCheck $them $this->themeHandler = $theme_handler; $this->menuLinkTree = $menu_link_tree; if ($module_extension_list === NULL) { - @trigger_error('The extension.list.module service must be passed to ' . __NAMESPACE__ . '\SystemController::__construct. It was added in Drupal 8.9.0 and will be required before Drupal 9.0.0.', E_USER_DEPRECATED); + @trigger_error('The extension.list.module service must be passed to ' . __NAMESPACE__ . '\SystemController::__construct. It was added in Drupal 8.9.0 and will be required before Drupal 10.0.0.', E_USER_DEPRECATED); $module_extension_list = \Drupal::service('extension.list.module'); } $this->moduleExtensionList = $module_extension_list; diff --git a/core/modules/system/tests/src/Functional/Theme/ThemeUiTest.php b/core/modules/system/tests/src/Functional/Theme/ThemeUiTest.php index 383acd46be..0414f3b63d 100644 --- a/core/modules/system/tests/src/Functional/Theme/ThemeUiTest.php +++ b/core/modules/system/tests/src/Functional/Theme/ThemeUiTest.php @@ -59,27 +59,17 @@ public function testModulePermissions() { * * @dataProvider providerTestThemeInstallWithModuleDependencies */ - public function testThemeInstallWithModuleDependencies( - $theme_name, - $first_expected_required_list_items, - $first_module_enable, - $first_confirm_checked, - $second_expected_required_list_items, - $second_module_enable, - $second_confirm_checked, - $disabled_attributes, - $required_by_messages, - $module_uninstall_message - ) { + public function testThemeInstallWithModuleDependencies($data) { + $theme_name = $data['theme_name']; $assert_session = $this->assertSession(); $page = $this->getSession()->getPage(); $this->drupalGet('admin/appearance'); - $this->assertUninstallableTheme($first_expected_required_list_items, $theme_name); + $this->assertUninstallableTheme($data['first_expected_required_list_items'], $theme_name); // Enable one of the two required modules. - $this->drupalPostForm('admin/modules', $first_module_enable, 'Install'); - foreach ($first_confirm_checked as $selector) { + $this->drupalPostForm('admin/modules', $data['first_module_enable'], 'Install'); + foreach ($data['first_confirm_checked'] as $selector) { $this->assertSession()->elementExists('css', $selector); } @@ -87,9 +77,9 @@ public function testThemeInstallWithModuleDependencies( // Confirm the theme is still uninstallable due to a remaining module // dependency. - $this->assertUninstallableTheme($second_expected_required_list_items, $theme_name); - $this->drupalPostForm('admin/modules', $second_module_enable, 'Install'); - foreach ($second_confirm_checked as $selector) { + $this->assertUninstallableTheme($data['second_expected_required_list_items'], $theme_name); + $this->drupalPostForm('admin/modules', $data['second_module_enable'], 'Install'); + foreach ($data['second_confirm_checked'] as $selector) { $this->assertSession()->elementExists('css', $selector); } @@ -102,34 +92,67 @@ public function testThemeInstallWithModuleDependencies( // Confirm that the dependee modules can't be uninstalled because an enabled // theme depends on them. $this->drupalGet('admin/modules/uninstall'); - foreach ($disabled_attributes as $attribute) { + foreach ($data['module_names'] as $attribute) { $assert_session->elementExists('css', "[name=\"uninstall[$attribute]\"][disabled]"); } - foreach ($required_by_messages as $selector => $message) { + foreach ($data['required_by_messages'] as $selector => $message) { $assert_session->elementTextContains('css', $selector, $message); } // Uninstall the theme that depends on the modules, and confirm the modules // can now be uninstalled. - $this->drupalGet('admin/appearance'); - $theme_to_uninstall = $theme_name === 'Test Theme with a Base Theme Depending on Modules' ? 'Test Theme Depending on Modules' : $theme_name; - $this->clickLink("Uninstall $theme_to_uninstall theme"); - $assert_session->pageTextContains("The $theme_to_uninstall theme has been uninstalled."); + $this->uninstallTheme($theme_name); $this->drupalGet('admin/modules/uninstall'); - foreach ($disabled_attributes as $attribute) { + // Only attempt to uninstall modules not required by the base theme. + $modules_to_uninstall = array_diff($data['module_names'], $data['base_theme_module_names']); + $this->uninstallModules($modules_to_uninstall, $data['module_uninstall_message']); + + if (!empty($data['base_theme_to_uninstall'])) { + $base_theme_name = $data['base_theme_to_uninstall']; + $this->uninstallTheme($base_theme_name); + $this->drupalGet('admin/modules/uninstall'); + $this->uninstallModules($data['base_theme_module_names'], $data['base_theme_module_uninstall_message']); + } + } + + /** + * Uninstalls modules via the admin UI. + * + * @param string[] $module_names + * An array of module machine names. + * @param string $confirmation_message_list + * The list of modules included in the confirmation. + */ + protected function uninstallModules(array $module_names, $confirmation_message_list) { + $assert_session = $this->assertSession(); + $this->drupalGet('admin/modules/uninstall'); + foreach ($module_names as $attribute) { $assert_session->elementExists('css', "[name=\"uninstall[$attribute]\"]:not([disabled])"); } $to_uninstall = []; - foreach ($disabled_attributes as $attribute) { + foreach ($module_names as $attribute) { $to_uninstall["uninstall[$attribute]"] = 1; } + if (!empty($to_uninstall)) { + $this->drupalPostForm('admin/modules/uninstall', $to_uninstall, 'Uninstall'); + $confirmation_message = 'The following modules will be completely uninstalled from your site, and all data from these modules will be lost!' . $confirmation_message_list . 'Would you like to continue with uninstalling the above?'; + $assert_session->pageTextContains($confirmation_message); + $this->getSession()->getPage()->pressButton('Uninstall'); + $assert_session->pageTextContains('The selected modules have been uninstalled.'); + } + } - $this->drupalPostForm('admin/modules/uninstall', $to_uninstall, 'Uninstall'); - $confirmation_message = 'The following modules will be completely uninstalled from your site, and all data from these modules will be lost!' . $module_uninstall_message . 'Would you like to continue with uninstalling the above?'; - $assert_session->pageTextContains($confirmation_message); - $page->pressButton('Uninstall'); - $assert_session->pageTextContains('The selected modules have been uninstalled.'); + /** + * Uninstalls a theme via the admin UI. + * + * @param string $theme_name + * The theme name. + */ + protected function uninstallTheme($theme_name) { + $this->drupalGet('admin/appearance'); + $this->clickLink("Uninstall $theme_name theme"); + $this->assertSession()->pageTextContains("The $theme_name theme has been uninstalled."); } /** @@ -138,139 +161,130 @@ public function testThemeInstallWithModuleDependencies( public function providerTestThemeInstallWithModuleDependencies() { return [ 'test theme with a module dependency and base theme with a different module dependency' => [ - // $theme_name. - 'Test Theme with a Module Dependency and Base Theme with a Different Module Dependency', - // $first_expected_required_list_items. - [ - 'Help (disabled)', - 'Test Module Required by Theme (disabled)', - 'Test Another Module Required by Theme (disabled)', - ], - // $first_module_enable. - [ - 'modules[test_module_required_by_theme][enable]' => 1, - 'modules[test_another_module_required_by_theme][enable]' => 1, - ], - // $first_confirm_checked. - [ - '#edit-modules-test-module-required-by-theme-enable[checked]', - '#edit-modules-test-another-module-required-by-theme-enable[checked]', - ], - // $second_expected_required_list_items. - [ - 'Help (disabled)', - 'Test Module Required by Theme', - 'Test Another Module Required by Theme', - ], - // $second_module_enable. - [ - 'modules[help][enable]' => 1, - ], - // $second_confirm_checked. - [ - '#edit-modules-test-module-required-by-theme-enable[checked]', - '#edit-modules-test-another-module-required-by-theme-enable[checked]', - '#edit-modules-help-enable[checked]', - ], - // $disabled_attributes. - [ - 'help', - ], - // $required_by_messages. [ - '[data-drupal-selector="edit-test-another-module-required-by-theme"] .item-list' => 'Required by the theme: test theme depending on modules', - '[data-drupal-selector="edit-test-module-required-by-theme"] .item-list' => 'Required by the theme: test theme depending on modules', - '[data-drupal-selector="edit-help"] .item-list' => 'Required by the theme: Test Theme with a Module Dependency and Base Theme with a Different Module Dependency', - + 'theme_name' => 'Test Theme with a Module Dependency and Base Theme with a Different Module Dependency', + 'first_expected_required_list_items' => [ + 'Help (disabled)', + 'Test Module Required by Theme (disabled)', + 'Test Another Module Required by Theme (disabled)', + ], + 'first_module_enable' => [ + 'modules[test_module_required_by_theme][enable]' => 1, + 'modules[test_another_module_required_by_theme][enable]' => 1, + ], + 'first_confirm_checked' => [ + '#edit-modules-test-module-required-by-theme-enable[checked]', + '#edit-modules-test-another-module-required-by-theme-enable[checked]', + ], + 'second_expected_required_list_items' => [ + 'Help (disabled)', + 'Test Module Required by Theme', + 'Test Another Module Required by Theme', + ], + 'second_module_enable' => [ + 'modules[help][enable]' => 1, + ], + 'second_confirm_checked' => [ + '#edit-modules-test-module-required-by-theme-enable[checked]', + '#edit-modules-test-another-module-required-by-theme-enable[checked]', + '#edit-modules-help-enable[checked]', + ], + 'module_names' => [ + 'help', + 'test_module_required_by_theme', + 'test_another_module_required_by_theme', + ], + 'required_by_messages' => [ + '[data-drupal-selector="edit-test-another-module-required-by-theme"] .item-list' => 'Required by the theme: Test Theme Depending on Modules', + '[data-drupal-selector="edit-test-module-required-by-theme"] .item-list' => 'Required by the theme: Test Theme Depending on Modules', + '[data-drupal-selector="edit-help"] .item-list' => 'Required by the theme: Test Theme with a Module Dependency and Base Theme with a Different Module Dependency', + ], + 'module_uninstall_message' => 'help', + 'base_theme_to_uninstall' => 'Test Theme Depending on Modules', + 'base_theme_module_names' => [ + 'test_module_required_by_theme', + 'test_another_module_required_by_theme', + ], + 'base_theme_module_uninstall_message' => 'Test Another Module Required by ThemeTest Module Required by Theme', ], - // $module_uninstall_message. - 'help', ], - 'test theme depending on modules' => [ - // $theme_name. - 'Test Theme Depending on Modules', - // $first_expected_required_list_items. - [ - 'Test Module Required by Theme (disabled)', - 'Test Another Module Required by Theme (disabled)', - ], - // $first_module_enable. - [ - 'modules[test_module_required_by_theme][enable]' => 1, - ], - // $first_confirm_checked. - [ - '#edit-modules-test-module-required-by-theme-enable[checked]', - ], - // $second_expected_required_list_items. - [ - 'Test Module Required by Theme', - 'Test Another Module Required by Theme (disabled)', - ], - // $second_module_enable. - [ - 'modules[test_another_module_required_by_theme][enable]' => 1, - ], - // $second_confirm_checked. - [ - '#edit-modules-test-module-required-by-theme-enable[checked]', - '#edit-modules-test-another-module-required-by-theme-enable[checked]', - ], - // $disabled_attributes. - [ - 'test_module_required_by_theme', - 'test_another_module_required_by_theme', - ], - // $required_by_messages. + 'Test Theme Depending on Modules' => [ [ - '[data-drupal-selector="edit-test-another-module-required-by-theme"] .item-list' => 'Required by the theme: test theme depending on modules', - '[data-drupal-selector="edit-test-module-required-by-theme"] .item-list' => 'Required by the theme: test theme depending on modules', + 'theme_name' => 'Test Theme Depending on Modules', + 'first_expected_required_list_items' => [ + 'Test Module Required by Theme (disabled)', + 'Test Another Module Required by Theme (disabled)', + ], + 'first_module_enable' => [ + 'modules[test_module_required_by_theme][enable]' => 1, + ], + 'first_confirm_checked' => [ + '#edit-modules-test-module-required-by-theme-enable[checked]', + ], + 'second_expected_required_list_items' => [ + 'Test Module Required by Theme', + 'Test Another Module Required by Theme (disabled)', + ], + 'second_module_enable' => [ + 'modules[test_another_module_required_by_theme][enable]' => 1, + ], + 'second_confirm_checked' => [ + '#edit-modules-test-module-required-by-theme-enable[checked]', + '#edit-modules-test-another-module-required-by-theme-enable[checked]', + ], + 'module_names' => [ + 'test_module_required_by_theme', + 'test_another_module_required_by_theme', + ], + 'required_by_messages' => [ + '[data-drupal-selector="edit-test-another-module-required-by-theme"] .item-list' => 'Required by the theme: Test Theme Depending on Modules', + '[data-drupal-selector="edit-test-module-required-by-theme"] .item-list' => 'Required by the theme: Test Theme Depending on Modules', + ], + 'module_uninstall_message' => 'Test Another Module Required by ThemeTest Module Required by Theme', + 'base_theme_to_uninstall' => '', + 'base_theme_module_names' => [], ], - // $module_uninstall_message. - 'test another module required by themetest module required by theme', ], 'test theme with a base theme depending on modules' => [ - // $theme_name. - 'Test Theme with a Base Theme Depending on Modules', - // $first_expected_required_list_items. - [ - 'Test Module Required by Theme (disabled)', - 'Test Another Module Required by Theme (disabled)', - ], - // $first_module_enable. - [ - 'modules[test_module_required_by_theme][enable]' => 1, - ], - // $first_confirm_checked. - [ - '#edit-modules-test-module-required-by-theme-enable[checked]', - ], - // $second_expected_required_list_items. - [ - 'Test Module Required by Theme', - 'Test Another Module Required by Theme (disabled)', - ], - // $second_module_enable. - [ - 'modules[test_another_module_required_by_theme][enable]' => 1, - ], - // $second_confirm_checked. - [ - '#edit-modules-test-module-required-by-theme-enable[checked]', - '#edit-modules-test-another-module-required-by-theme-enable[checked]', - ], - // $disabled_attributes. - [ - 'test_module_required_by_theme', - 'test_another_module_required_by_theme', - ], - // $required_by_messages. [ - '[data-drupal-selector="edit-test-another-module-required-by-theme"] .item-list' => 'Required by the theme: test theme depending on modules', - '[data-drupal-selector="edit-test-module-required-by-theme"] .item-list' => 'Required by the theme: test theme depending on modules', + 'theme_name' => 'Test Theme with a Base Theme Depending on Modules', + 'first_expected_required_list_items' => [ + 'Test Module Required by Theme (disabled)', + 'Test Another Module Required by Theme (disabled)', + ], + 'first_module_enable' => [ + 'modules[test_module_required_by_theme][enable]' => 1, + ], + 'first_confirm_checked' => [ + '#edit-modules-test-module-required-by-theme-enable[checked]', + ], + 'second_expected_required_list_items' => [ + 'Test Module Required by Theme', + 'Test Another Module Required by Theme (disabled)', + ], + 'second_module_enable' => [ + 'modules[test_another_module_required_by_theme][enable]' => 1, + ], + 'second_confirm_checked' => [ + '#edit-modules-test-module-required-by-theme-enable[checked]', + '#edit-modules-test-another-module-required-by-theme-enable[checked]', + ], + 'module_names' => [ + 'test_module_required_by_theme', + 'test_another_module_required_by_theme', + ], + 'required_by_messages' => [ + '[data-drupal-selector="edit-test-another-module-required-by-theme"] .item-list' => 'Required by the theme: Test Theme Depending on Modules', + '[data-drupal-selector="edit-test-module-required-by-theme"] .item-list' => 'Required by the theme: Test Theme Depending on Modules', + ], + 'module_uninstall_message' => '', + 'base_theme_to_uninstall' => 'Test Theme Depending on Modules', + 'base_theme_module_names' => [ + 'test_module_required_by_theme', + 'test_another_module_required_by_theme', + ], + 'base_theme_module_uninstall_message' => 'Test Another Module Required by ThemeTest Module Required by Theme', ], - // $module_uninstall_message. - 'test another module required by themetest module required by theme', ], ]; } diff --git a/core/tests/Drupal/KernelTests/Core/Theme/ThemeInstallerTest.php b/core/tests/Drupal/KernelTests/Core/Theme/ThemeInstallerTest.php index 30a7ba7841..df6f607d26 100644 --- a/core/tests/Drupal/KernelTests/Core/Theme/ThemeInstallerTest.php +++ b/core/tests/Drupal/KernelTests/Core/Theme/ThemeInstallerTest.php @@ -158,27 +158,27 @@ public function testInstallThemeWithUnmetModuleDependencies($theme_name, $missin */ public function providerTestInstallThemeWithUnmetModuleDependencies() { return [ - 'test_theme_depending_on_modules' => [ + 'theme with uninstalled module dependencies' => [ 'test_theme_depending_on_modules', 'test_module_required_by_theme, test_another_module_required_by_theme.', [], ], - 'test_theme_with_a_base_theme_depending_on_modules' => [ + 'theme with a base theme with uninstalled module dependencies' => [ 'test_theme_with_a_base_theme_depending_on_modules', 'test_module_required_by_theme, test_another_module_required_by_theme.', [], ], - 'test_theme_mixed_module_dependencies' => [ + 'theme and base theme have uninstalled module dependencies' => [ 'test_theme_mixed_module_dependencies', 'help, test_module_required_by_theme, test_another_module_required_by_theme.', [], ], - 'test_theme_mixed_module_dependencies - node enabled' => [ + 'theme with already installed module dependencies, base theme module dependencies are not installed' => [ 'test_theme_mixed_module_dependencies', 'test_module_required_by_theme, test_another_module_required_by_theme.', ['help'], ], - 'test_theme_mixed_module_dependencies - test modules enabled' => [ + 'theme with module dependencies not installed, base theme module dependencies are already installed, ' => [ 'test_theme_mixed_module_dependencies', 'help.', ['test_module_required_by_theme', 'test_another_module_required_by_theme'],