From 59ee80c47486351a98ae63cad01485a4e34c2d1e Mon Sep 17 00:00:00 2001 From: phenaproxima <phenaproxima@205645.no-reply.drupal.org> Date: Tue, 21 Jun 2022 16:09:51 +0000 Subject: [PATCH] Issue #3264849 by tedbow, phenaproxima: Show next minor or current minor updates in Update form --- automatic_updates.module | 12 +- src/Form/UpdaterForm.php | 269 ++++++++++++------ tests/src/Build/CoreUpdateTest.php | 2 +- .../Functional/AvailableUpdatesReportTest.php | 4 +- tests/src/Functional/UpdaterFormTest.php | 119 ++++++-- 5 files changed, 295 insertions(+), 111 deletions(-) diff --git a/automatic_updates.module b/automatic_updates.module index 17b39d9db6..bfb47fef89 100644 --- a/automatic_updates.module +++ b/automatic_updates.module @@ -197,10 +197,16 @@ function automatic_updates_preprocess_update_project_status(array &$variables) { return; } $updater = \Drupal::service('automatic_updates.updater'); + $supported_target_versions = []; /** @var \Drupal\automatic_updates\ReleaseChooser $recommender */ $recommender = \Drupal::service('automatic_updates.release_chooser'); try { - $supported_update_release = $recommender->getLatestInInstalledMinor($updater) ?? $recommender->getLatestInNextMinor($updater); + if ($installed_minor_release = $recommender->getLatestInInstalledMinor($updater)) { + $supported_target_versions[] = $installed_minor_release->getVersion(); + } + if ($next_minor_release = $recommender->getLatestInNextMinor($updater)) { + $supported_target_versions[] = $next_minor_release->getVersion(); + } } catch (RuntimeException $exception) { // If for some reason we are not able to get the update recommendations @@ -211,7 +217,7 @@ function automatic_updates_preprocess_update_project_status(array &$variables) { $variables['#attached']['library'][] = 'automatic_updates/update_status'; $status = &$variables['status']; - if ($supported_update_release && $status['label']) { + if ($supported_target_versions && $status['label']) { $status['label'] = [ '#markup' => t( '@label <a href=":update-form">Update now</a>', [ @@ -226,7 +232,7 @@ function automatic_updates_preprocess_update_project_status(array &$variables) { } foreach ($variables['versions'] as &$themed_version) { $version_info = &$themed_version['#version']; - if ($supported_update_release && $version_info['version'] === $supported_update_release->getVersion()) { + if ($supported_target_versions && in_array($version_info['version'], $supported_target_versions, TRUE)) { $version_info['download_link'] = Url::fromRoute('automatic_updates.report_update')->setAbsolute()->toString(); } else { diff --git a/src/Form/UpdaterForm.php b/src/Form/UpdaterForm.php index 2074fe1153..95c8e96398 100644 --- a/src/Form/UpdaterForm.php +++ b/src/Form/UpdaterForm.php @@ -8,13 +8,15 @@ use Drupal\automatic_updates\ProjectInfo; use Drupal\automatic_updates\ReleaseChooser; use Drupal\automatic_updates\Updater; use Drupal\automatic_updates\Validation\ReadinessTrait; +use Drupal\automatic_updates_9_3_shim\ProjectRelease; use Drupal\Core\Batch\BatchBuilder; +use Drupal\Core\Extension\ExtensionVersion; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Link; use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Render\RendererInterface; use Drupal\Core\State\StateInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Url; use Drupal\package_manager\Exception\StageException; use Drupal\package_manager\Exception\StageOwnershipException; @@ -28,9 +30,9 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; * Defines a form to update Drupal core. * * @internal - * Form classes are internal. + * Form classes are internal and the form structure may change at any time. */ -class UpdaterForm extends FormBase { +final class UpdaterForm extends FormBase { use ReadinessTrait { formatResult as traitFormatResult; @@ -154,10 +156,8 @@ class UpdaterForm extends FormBase { // one release on the form. First, try to show the latest release in the // currently installed minor. Failing that, try to show the latest // release in the next minor. - $recommended_release = $this->releaseChooser->getLatestInInstalledMinor($this->updater); - if (!$recommended_release) { - $recommended_release = $this->releaseChooser->getLatestInNextMinor($this->updater); - } + $installed_minor_release = $this->releaseChooser->getLatestInInstalledMinor($this->updater); + $next_minor_release = $this->releaseChooser->getLatestInNextMinor($this->updater); } catch (\RuntimeException $e) { $form['message'] = [ @@ -170,7 +170,7 @@ class UpdaterForm extends FormBase { $form['#attached']['library'][] = 'update/drupal.update.admin'; $project = $project_info->getProjectInfo(); - if ($recommended_release === NULL) { + if ($installed_minor_release === NULL && $next_minor_release === NULL) { if ($project['status'] === UpdateManagerInterface::CURRENT) { $this->messenger()->addMessage($this->t('No update available')); } @@ -186,92 +186,91 @@ class UpdaterForm extends FormBase { return $form; } - $form['target_version'] = [ - '#type' => 'value', - '#value' => [ - 'drupal' => $recommended_release->getVersion(), - ], - ]; - if (empty($project['title']) || empty($project['link'])) { throw new \UnexpectedValueException('Expected project data to have a title and link.'); } - $title = Link::fromTextAndUrl($project['title'], Url::fromUri($project['link']))->toRenderable(); + + $form['title'] = [ + '#type' => 'html_tag', + '#tag' => 'h2', + '#value' => $this->t( + 'Update <a href=":url">Drupal core</a>', + [':url' => $project['link']], + ), + ]; + $form['current'] = [ + '#type' => 'html_tag', + '#tag' => 'p', + '#value' => $this->t( + 'Currently installed: @version (@status)', + [ + '@version' => $project_info->getInstalledVersion(), + '@status' => $this->getUpdateStatus($project['status']), + ] + ), + ]; switch ($project['status']) { case UpdateManagerInterface::NOT_SECURE: case UpdateManagerInterface::REVOKED: - $title['#suffix'] = ' ' . $this->t('(Security update)'); + $release_status = $this->t('Security update'); $type = 'update-security'; break; - case UpdateManagerInterface::NOT_SUPPORTED: - $title['#suffix'] = ' ' . $this->t('(Unsupported)'); - $type = 'unsupported'; - break; - default: - $type = 'recommended'; - break; + $release_status = $this->t('Available update'); + $type = 'update-recommended'; } - - // Create an entry for this project. - $entry = [ - 'title' => [ - 'data' => $title, - ], - 'installed_version' => $project_info->getInstalledVersion(), - 'recommended_version' => [ - 'data' => [ - // @todo Is an inline template the right tool here? Is there an Update - // module template we should use instead? - '#type' => 'inline_template', - '#template' => '{{ release_version }} (<a href="{{ release_link }}" title="{{ project_title }}">{{ release_notes }}</a>)', - '#context' => [ - 'release_version' => $recommended_release->getVersion(), - 'release_link' => $recommended_release->getReleaseUrl(), - 'project_title' => $this->t('Release notes for @project_title', ['@project_title' => $project['title']]), - 'release_notes' => $this->t('Release notes'), - ], - ], - ], - ]; - - $form['projects'] = [ - '#type' => 'table', - '#header' => [ - 'title' => [ - 'data' => $this->t('Name'), - 'class' => ['update-project-name'], - ], - 'installed_version' => $this->t('Installed version'), - 'recommended_version' => [ - 'data' => $this->t('Recommended version'), - ], - ], - '#rows' => [ - 'drupal' => [ - 'class' => "update-$type", - 'data' => $entry, - ], - ], - ]; - - $form['backup'] = [ - '#markup' => $this->t('It\'s a good idea to <a href=":url">back up your database</a> before you begin.', [':url' => 'https://www.drupal.org/node/22281#s-backing-up-the-database']), - ]; - if ($form_state->getUserInput()) { $results = []; } else { - $event = new ReadinessCheckEvent($this->updater, [ - 'drupal' => $recommended_release->getVersion(), - ]); + $event = new ReadinessCheckEvent($this->updater); $this->eventDispatcher->dispatch($event); $results = $event->getResults(); } $this->displayResults($results, $this->messenger(), $this->renderer); + $create_update_buttons = !$stage_exists && $this->getOverallSeverity($results) !== SystemManager::REQUIREMENT_ERROR; + if ($installed_minor_release) { + $installed_version = ExtensionVersion::createFromVersionString($project_info->getInstalledVersion()); + $form['installed_minor'] = $this->createReleaseTable( + $installed_minor_release, + $release_status, + $this->t('Latest version of Drupal @major.@minor (currently installed):', [ + '@major' => $installed_version->getMajorVersion(), + '@minor' => $installed_version->getMinorVersion(), + ]), + $type, + $create_update_buttons, + // Any update in the current minor should be the primary update. + TRUE, + ); + } + if ($next_minor_release) { + // If there is no update in the current minor make the button for the next + // minor primary unless the project status is 'CURRENT' or 'NOT_CURRENT'. + // 'NOT_CURRENT' does not denote that installed version is not a valid + // only that there is newer version available. + $is_primary = !$installed_minor_release && !($project['status'] === UpdateManagerInterface::CURRENT || $project['status'] === UpdateManagerInterface::NOT_CURRENT); + $next_minor_version = ExtensionVersion::createFromVersionString($next_minor_release->getVersion()); + // @todo Add documentation to explain what is different about a minor + // update in https://www.drupal.org/i/3291730. + $form['next_minor'] = $this->createReleaseTable( + $next_minor_release, + $installed_minor_release ? $this->t('Minor update') : $release_status, + $this->t('Latest version of Drupal @major.@minor (next minor):', [ + '@major' => $next_minor_version->getMajorVersion(), + '@minor' => $next_minor_version->getMinorVersion(), + ]), + $installed_minor_release ? 'update-optional' : $type, + $create_update_buttons, + $is_primary + ); + } + + $form['backup'] = [ + '#markup' => $this->t('It\'s a good idea to <a href=":url">back up your database</a> before you begin.', [':url' => 'https://www.drupal.org/node/22281#s-backing-up-the-database']), + ]; if ($stage_exists) { // If the form has been submitted, do not display this error message @@ -286,13 +285,6 @@ class UpdaterForm extends FormBase { '#submit' => ['::deleteExistingUpdate'], ]; } - // If there were no errors, allow the user to proceed with the update. - elseif ($this->getOverallSeverity($results) !== SystemManager::REQUIREMENT_ERROR) { - $form['actions']['submit'] = [ - '#type' => 'submit', - '#value' => $this->t('Update'), - ]; - } $form['actions']['#type'] = 'actions'; return $form; @@ -315,12 +307,13 @@ class UpdaterForm extends FormBase { * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { + $button = $form_state->getTriggeringElement(); $batch = (new BatchBuilder()) ->setTitle($this->t('Downloading updates')) ->setInitMessage($this->t('Preparing to download updates')) ->addOperation( [BatchProcessor::class, 'begin'], - [$form_state->getValue('target_version')] + [['drupal' => $button['#target_version']]] ) ->addOperation([BatchProcessor::class, 'stage']) ->setFinishCallback([BatchProcessor::class, 'finishStage']) @@ -345,4 +338,116 @@ class UpdaterForm extends FormBase { return $this->traitFormatResult($result); } + /** + * Gets the update table for a specific release. + * + * @param \Drupal\automatic_updates_9_3_shim\ProjectRelease $release + * The project release. + * @param string $release_description + * The release description. + * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $caption + * The table caption, if any. + * @param string $update_type + * The update type. + * @param bool $create_update_button + * Whether the update button should be created. + * @param bool $is_primary + * Whether update button should be a primary button. + * + * @return array + * The table render array. + */ + private function createReleaseTable(ProjectRelease $release, string $release_description, ?TranslatableMarkup $caption, string $update_type, bool $create_update_button, bool $is_primary): array { + $release_section = ['#type' => 'container']; + $release_section['table'] = [ + '#type' => 'table', + '#description' => $this->t('more'), + '#header' => [ + 'title' => [ + 'data' => $this->t('Update type'), + 'class' => ['update-project-name'], + ], + 'target_version' => [ + 'data' => $this->t('Version'), + ], + ], + ]; + if ($caption) { + $release_section['table']['#caption'] = $caption; + } + $release_section['table'][$release->getVersion()] = [ + 'title' => [ + '#type' => 'html_tag', + '#tag' => 'p', + '#value' => $release_description, + ], + 'target_version' => [ + 'data' => [ + // @todo Is an inline template the right tool here? Is there an Update + // module template we should use instead? + '#type' => 'inline_template', + '#template' => '{{ release_version }} (<a href="{{ release_link }}" title="{{ project_title }}">{{ release_notes }}</a>)', + '#context' => [ + 'release_version' => $release->getVersion(), + 'release_link' => $release->getReleaseUrl(), + 'project_title' => $this->t( + 'Release notes for @project_title @version', + [ + '@project_title' => 'Drupal core', + '@version' => $release->getVersion(), + ] + ), + 'release_notes' => $this->t('Release notes'), + ], + ], + ], + '#attributes' => ['class' => ['update-' . $update_type]], + ]; + if ($create_update_button) { + $release_section['submit'] = [ + '#type' => 'submit', + '#value' => $this->t('Update to @version', ['@version' => $release->getVersion()]), + '#target_version' => $release->getVersion(), + ]; + if ($is_primary) { + $release_section['submit']['#button_type'] = 'primary'; + } + } + $release_section['#suffix'] = '<br />'; + return $release_section; + + } + + /** + * Gets the human-readable project status. + * + * @param int $status + * The project status, one of \Drupal\update\UpdateManagerInterface + * constants. + * + * @return \Drupal\Core\StringTranslation\TranslatableMarkup + * The human-readable status. + */ + private function getUpdateStatus(int $status): TranslatableMarkup { + switch ($status) { + case UpdateManagerInterface::NOT_SECURE: + return $this->t('Security update required!'); + + case UpdateManagerInterface::REVOKED: + return $this->t('Revoked!'); + + case UpdateManagerInterface::NOT_SUPPORTED: + return $this->t('Not supported!'); + + case UpdateManagerInterface::NOT_CURRENT: + return $this->t('Update available'); + + case UpdateManagerInterface::CURRENT: + return $this->t('Up to date'); + + default: + return $this->t('Unknown status'); + } + } + } diff --git a/tests/src/Build/CoreUpdateTest.php b/tests/src/Build/CoreUpdateTest.php index 7e32c651fb..61e18bbe85 100644 --- a/tests/src/Build/CoreUpdateTest.php +++ b/tests/src/Build/CoreUpdateTest.php @@ -109,7 +109,7 @@ class CoreUpdateTest extends UpdateTestBase { $session->reload(); $assert_session->pageTextNotContains('There is a security update available for your version of Drupal.'); - $page->pressButton('Update'); + $page->pressButton('Update to 9.8.1'); $this->waitForBatchJob(); $assert_session->pageTextContains('Ready to update'); $page->pressButton('Continue'); diff --git a/tests/src/Functional/AvailableUpdatesReportTest.php b/tests/src/Functional/AvailableUpdatesReportTest.php index 08ae40ee7a..2052512d4b 100644 --- a/tests/src/Functional/AvailableUpdatesReportTest.php +++ b/tests/src/Functional/AvailableUpdatesReportTest.php @@ -68,7 +68,7 @@ class AvailableUpdatesReportTest extends AutomaticUpdatesFunctionalTestBase { $assert->elementAttributeContains('named', ['link', 'Update now'], 'href', $form_url); // Releases that will available on the form should link to the form. - $this->assertVersionLink('9.8.2', 'http://example.com/drupal-9-8-2-release'); + $this->assertVersionLink('9.8.2', $form_url); $this->assertVersionLink('9.7.1', $form_url); // Releases that will not be available in the form should link to the // project release page. @@ -78,7 +78,7 @@ class AvailableUpdatesReportTest extends AutomaticUpdatesFunctionalTestBase { $this->checkForUpdates(); $assert->pageTextContains('Update available Update now'); $assert->elementAttributeContains('named', ['link', 'Update now'], 'href', $form_url); - $this->assertVersionLink('9.8.2', 'http://example.com/drupal-9-8-2-release'); + $this->assertVersionLink('9.8.2', $form_url); } /** diff --git a/tests/src/Functional/UpdaterFormTest.php b/tests/src/Functional/UpdaterFormTest.php index 7bbb2254bc..dc485c4fd9 100644 --- a/tests/src/Functional/UpdaterFormTest.php +++ b/tests/src/Functional/UpdaterFormTest.php @@ -117,7 +117,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $assert_session = $this->assertSession(); $assert_session->pageTextContains('No update available'); - $assert_session->buttonNotExists('Update'); + $this->assertNoUpdateButtons(); } /** @@ -131,6 +131,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { * @dataProvider providerTableLooksCorrect */ public function testTableLooksCorrect(string $access_page): void { + $page = $this->getSession()->getPage(); $this->drupalPlaceBlock('local_tasks_block', ['primary' => TRUE]); $assert_session = $this->assertSession(); $this->setCoreVersion('9.8.0'); @@ -148,17 +149,82 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $this->clickLink('Available updates'); } $this->clickLink('Update'); + + // Check the form when there is an updates in the next minor only. + $assert_session->pageTextContainsOnce('Currently installed: 9.8.0 (Security update required!)'); + $this->checkReleaseTable('#edit-installed-minor', '.update-update-security', '9.8.1', TRUE, 'Latest version of Drupal 9.8 (currently installed):'); + $assert_session->elementNotExists('css', '#edit-next-minor'); + + // Check the form when there is an updates in the next minor only. + $this->config('automatic_updates.settings')->set('allow_core_minor_updates', TRUE)->save(); + $this->setCoreVersion('9.7.0'); + $page->clickLink('Check manually'); + $this->checkForMetaRefresh(); + $this->checkReleaseTable('#edit-next-minor', '.update-update-recommended', '9.8.1', TRUE, 'Latest version of Drupal 9.8 (next minor):'); + $assert_session->pageTextContainsOnce('Currently installed: 9.7.0 (Not supported!)'); + $assert_session->elementNotExists('css', '#edit-installed-minor'); + + // Check the form when there are updates in the current and next minors but + // the site does not support minor updates. + $this->config('automatic_updates.settings')->set('allow_core_minor_updates', FALSE)->save(); + $this->setReleaseMetadata(__DIR__ . '/../../fixtures/release-history/drupal.9.8.2.xml'); + $page->clickLink('Check manually'); + $this->checkForMetaRefresh(); + $assert_session->pageTextContainsOnce('Currently installed: 9.7.0 (Update available)'); + $this->checkReleaseTable('#edit-installed-minor', '.update-update-recommended', '9.7.1', TRUE, 'Latest version of Drupal 9.7 (currently installed):'); + $assert_session->elementNotExists('css', '#edit-next-minor'); + + // Check that if minor updates are enabled the update in the next minor will + // be visible. + $this->config('automatic_updates.settings')->set('allow_core_minor_updates', TRUE)->save(); + $this->getSession()->reload(); + $this->checkReleaseTable('#edit-installed-minor', '.update-update-recommended', '9.7.1', TRUE, 'Latest version of Drupal 9.7 (currently installed):'); + $this->checkReleaseTable('#edit-next-minor', '.update-update-optional', '9.8.2', FALSE, 'Latest version of Drupal 9.8 (next minor):'); + + $this->setCoreVersion('9.7.1'); + $page->clickLink('Check manually'); + $this->checkForMetaRefresh(); + $assert_session->pageTextContainsOnce('Currently installed: 9.7.1 (Update available)'); + $assert_session->elementNotExists('css', '#edit-installed-minor'); + $this->checkReleaseTable('#edit-next-minor', '.update-update-recommended', '9.8.2', FALSE, 'Latest version of Drupal 9.8 (next minor):'); + + $this->assertUpdateStagedTimes(0); + } + + /** + * Checks the table for a release on the form. + * + * @param string $container_locator + * The CSS locator for the element with contains the table. + * @param string $row_class + * The row class for the update. + * @param string $version + * The release version number. + * @param bool $is_primary + * Whether update button should be a primary button. + * @param string|null $table_caption + * The table caption or NULL if none expected. + */ + private function checkReleaseTable(string $container_locator, string $row_class, string $version, bool $is_primary, ?string $table_caption = NULL): void { + $assert_session = $this->assertSession(); $assert_session->pageTextNotContains('There is a security update available for your version of Drupal.'); - $cells = $assert_session->elementExists('css', '#edit-projects .update-update-security') + $assert_session->linkExists('Drupal core'); + $container = $assert_session->elementExists('css', $container_locator); + if ($table_caption) { + $this->assertSame($table_caption, $assert_session->elementExists('css', 'caption', $container)->getText()); + } + else { + $assert_session->elementNotExists('css', 'caption', $container); + } + + $cells = $assert_session->elementExists('css', $row_class, $container) ->findAll('css', 'td'); - $this->assertCount(3, $cells); - $assert_session->elementExists('named', ['link', 'Drupal'], $cells[0]); - $this->assertSame('9.8.0', $cells[1]->getText()); - $this->assertSame('9.8.1 (Release notes)', $cells[2]->getText()); - $release_notes = $assert_session->elementExists('named', ['link', 'Release notes'], $cells[2]); - $this->assertSame('Release notes for Drupal', $release_notes->getAttribute('title')); - $assert_session->buttonExists('Update'); - $this->assertUpdateStagedTimes(0); + $this->assertCount(2, $cells); + $this->assertSame("$version (Release notes)", $cells[1]->getText()); + $release_notes = $assert_session->elementExists('named', ['link', 'Release notes'], $cells[1]); + $this->assertSame("Release notes for Drupal core $version", $release_notes->getAttribute('title')); + $button = $assert_session->buttonExists("Update to $version", $container); + $this->assertSame($is_primary, $button->hasClass('button--primary')); } /** @@ -186,7 +252,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { // If a validator raises an error during readiness checking, the form should // not have a submit button. $this->drupalGet('/admin/modules/automatic-update'); - $assert_session->buttonNotExists('Update'); + $this->assertNoUpdateButtons(); // Since this is an administrative page, the error message should be visible // thanks to automatic_updates_page_top(). The readiness checks were re-run // during the form build, which means the new error should be cached and @@ -206,7 +272,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $assert_session->pageTextNotContains(static::$errorsExplanation); $assert_session->pageTextNotContains(static::$warningsExplanation); $assert_session->pageTextNotContains($cached_message); - $page->pressButton('Update'); + $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); $this->assertUpdateStagedTimes(0); $assert_session->pageTextContainsOnce('An error has occurred.'); @@ -225,7 +291,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { // If a validator flags an error, but doesn't throw, the update should still // be halted. TestSubscriber1::setTestResult($expected_results, PreCreateEvent::class); - $page->pressButton('Update'); + $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); $this->assertUpdateStagedTimes(0); $assert_session->pageTextContainsOnce('An error has occurred.'); @@ -254,7 +320,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $assert_session->pageTextContains('Updates were found, but they must be performed manually. See the list of available updates for more information.'); $this->clickLink('the list of available updates'); $assert_session->elementExists('css', 'table.update'); - $assert_session->buttonNotExists('Update'); + $this->assertNoUpdateButtons(); } /** @@ -271,7 +337,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $this->drupalGet('/admin/modules/automatic-update'); FixtureStager::setFixturePath(__DIR__ . '/../../fixtures/staged/9.8.1'); - $page->pressButton('Update'); + $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); $this->assertUpdateStagedTimes(1); @@ -290,7 +356,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $assert_session->pageTextContains($cancelled_message); $assert_session->pageTextNotContains($conflict_message); // Ensure we can start another update after deleting the existing one. - $page->pressButton('Update'); + $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); // Confirm we are on the confirmation page. @@ -304,12 +370,12 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $this->drupalLogin($account); $this->drupalGet('/admin/reports/updates/automatic-update'); $assert_session->pageTextContains($conflict_message); - $assert_session->buttonNotExists('Update'); + $this->assertNoUpdateButtons(); // We should be able to delete the previous update, then start a new one. $page->pressButton('Delete existing update'); $assert_session->pageTextContains('Staged update deleted'); $assert_session->pageTextNotContains($conflict_message); - $page->pressButton('Update'); + $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); $this->assertUpdateReady('9.8.1'); @@ -355,7 +421,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $this->createTestValidationResults(); $results = $this->testResults['checker_1']['1 error']; TestSubscriber1::setTestResult($results, PreApplyEvent::class); - $page->pressButton('Update'); + $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); $this->assertUpdateReady('9.8.1'); $page->pressButton('Continue'); @@ -409,7 +475,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $assert_session = $this->assertSession(); $assert_session->pageTextContains(reset($messages)); $assert_session->pageTextNotContains($cached_message); - $page->pressButton('Update'); + $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); $this->assertUpdateStagedTimes(1); $this->assertUpdateReady('9.8.1'); @@ -506,7 +572,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $this->drupalGet($update_form_url); FixtureStager::setFixturePath(__DIR__ . '/../../fixtures/staged/9.8.1'); $assert_session->pageTextNotContains($cached_message); - $page->pressButton('Update'); + $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); $this->assertUpdateStagedTimes(1); $this->assertUpdateReady('9.8.1'); @@ -534,7 +600,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { $page = $this->getSession()->getPage(); $this->drupalGet('/admin/modules/automatic-update'); FixtureStager::setFixturePath(__DIR__ . '/../../fixtures/staged/9.8.1'); - $page->pressButton('Update'); + $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); $this->assertUpdateStagedTimes(1); $this->assertUpdateReady('9.8.1'); @@ -574,7 +640,7 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { TestSubscriber1::setException($error, PostRequireEvent::class); $assert_session->pageTextNotContains(static::$errorsExplanation); $assert_session->pageTextNotContains(static::$warningsExplanation); - $page->pressButton('Update'); + $page->pressButton('Update to 9.8.1'); $this->checkForMetaRefresh(); $this->assertUpdateStagedTimes(1); $assert_session->pageTextContainsOnce('An error has occurred.'); @@ -610,4 +676,11 @@ class UpdaterFormTest extends AutomaticUpdatesFunctionalTestBase { return $message; } + /** + * Asserts that no update buttons exist. + */ + private function assertNoUpdateButtons(): void { + $this->assertSession()->elementNotExists('css', "input[value*='Update']"); + } + } -- GitLab