Problem/Motivation

This issue is part of #2974445: [Meta] Refactor Migrate Drupal UI Functional tests.

Currently, the base classes MigrateUpgradeTestBase and MigrateUpgradeExecuteTestBase define test methods, and these are customized by other methods that are overridden in the child classes. We want to move to a more common structure, where the base classes define assertion methods and other helper functions and the child classes define the tests.

This issue adds those assertion methods and other helper functions to MigrateUpgradeTestBase. Eventually, we plan to remove MigrateUpgradeExecuteTestBase.

Proposed resolution

Add helper methods to test

  • IdConflictForm
  • ReviewForm

Note that there are assertions in the old assertReviewPage() regarding the source provider that are not moved to assertReviewForm(). Those assertions are still done in MultilingualReviewPageTestBase and NoMultilingualReviewPageTestBase, so we have not lost test coverage. There is a new issue to create a separate test of the source provider: #3143721: Create a separate SourceProviderTest.

In addition,

  • Move the $destinationSiteVersion property from MigrateUpgradeExecuteTestBase to MigrateUpgradeTestBase.
  • Add the helper function assertUserLogIn().

Remaining tasks

User interface changes

None

API changes

None

Data model changes

None

Original report by [username]

Create methods for each form to do any assertions needed for that form.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

quietone created an issue. See original summary.

quietone’s picture

Status: Active » Needs review
FileSize
17.6 KB

Status: Needs review » Needs work

The last submitted patch, 2: 3143717-2.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

quietone’s picture

Status: Needs work » Needs review
FileSize
1.24 KB
18.12 KB
quietone’s picture

+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeExecuteTestBase.php
@@ -21,7 +21,7 @@ abstract class MigrateUpgradeExecuteTestBase extends MigrateUpgradeTestBase {
+  protected function setUp(): void {

+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
@@ -34,7 +35,7 @@ abstract class MigrateUpgradeTestBase extends BrowserTestBase {
+  protected function setUp(): void {

@@ -92,7 +93,7 @@ protected function createMigrationConnection() {
+  protected function tearDown(): void {

Remove out of scope changes

quietone’s picture

Fix hard coded instance of 'Drupal 9'.

benjifisher’s picture

Status: Needs review » Needs work

I started looking at this patch. Here are some initial suggestions. I may have more when I re-review.

  1. Let me add some lines of context to what I see in the patch:

     +++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeExecuteTestBase.php
     @@ -11,13 +11,6 @@ abstract class MigrateUpgradeExecuteTestBase extends MigrateUpgradeTestBase {
     ...
     -  /**
     -   * The destination site major version.
     -   *
     -   * @var string
     -   */
     -  protected $destinationSiteVersion;
    
        /**
         * {@inheritdoc}
         */
        protected function setUp() {
          parent::setUp();
    
          // Create content.
          $this->createContent();
    
          // Get the current major version.
          [$this->destinationSiteVersion] = explode('.', \Drupal::VERSION, 2);
        }
     +++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
     @@ -31,6 +32,13 @@ abstract class MigrateUpgradeTestBase extends BrowserTestBase {
         */
        protected $sourceDatabase;
    
     +  /**
     +   * The destination site major version.
     +   *
     +   * @var string
     +   */
     +  protected $destinationSiteVersion;

    Without looking at it too closely: if we are moving this property to the parent class, should we also move the lines in setUp() that set its value?

  2.   diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
      @@ -165,39 +173,19 @@ protected function assertUpgradePaths(WebAssert $session, array $available_paths
      -  protected function assertIdConflict(WebAssert $session, array $entity_types) {
      -    /** @var \Drupal\ $entity_type_manager */
      +  protected function assertIdConflictForm(WebAssert $session, array $entity_types) {
      +    /** @var \Drupal\Core\Entity\EntityTypeManager $entity_type_manager */

    Search for "assertIdConflict". It is used in an assertion message in this file. I have not checked other files.

  3.   +++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
      @@ -260,4 +248,83 @@ protected function assertMigrationResults(array $expected_counts, $version) {
      +   * @throws \Behat\Mink\Exception\ExpectationException
      +   */
      +  protected function assertReviewForm(WebAssert $session, array $available_paths, array $missing_paths) {
      +    $this->assertSession()->pageTextContains('What will be upgraded?');
      +    $this->assertUpgradePaths($session, $available_paths, $missing_paths);
      +  }

    Do we need an @throw annotation when an exception might be thrown indirectly (i.e., from a function that this function calls)? Do we need this function at all, or can we add the additional assertion to assertUpgradePaths()? (I have not checked.) If we do need this function, then why not use $session instead of $this->assertSession()?

  4.   diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
      @@ -165,39 +173,19 @@ protected function assertUpgradePaths(WebAssert $session, array $available_paths
      ...
      -  protected function assertReviewPage(WebAssert $session, array $available_paths, array $missing_paths) {
      -    $this->assertText('What will be upgraded?');
      -
      -    // Ensure there are no errors about the missing modules from the test module.
      -    $session->pageTextNotContains(t('Source module not found for migration_provider_no_annotation.'));
      -    $session->pageTextNotContains(t('Source module not found for migration_provider_test.'));
      -    $session->pageTextNotContains(t('Destination module not found for migration_provider_test'));

    It looks as though that last assertion is not replaced.

quietone’s picture

Status: Needs work » Needs review
FileSize
3.44 KB
19.2 KB

1. Yes, that makes sense. Done.
2. I don't think the message is needed so have removed it.
3. Adding the @throws PhpStorm to stop complaining. Passing $session and using it in all the helpers now.
4. Yes, this is another case where assertions are repeated in several tests. These assertions still exist in MultilingualReviewPageTestBase and NoMultilingualReviewPageTestBase and they will be moved to their own test in #3143721: Create a separate SourceProviderTest.

quietone’s picture

Issue summary: View changes

Update IS with info from #8.4.

benjifisher’s picture

Status: Needs review » Needs work

Thanks for making those changes. I have a few more suggestions.

  1.   diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
      @@ -260,4 +251,85 @@ protected function assertMigrationResults(array $expected_counts, $version) {
      +  protected function assertReviewForm(WebAssert $session, array $available_paths, array $missing_paths) {
      +    $session->pageTextContains('What will be upgraded?');
      +    $this->assertUpgradePaths($session, $available_paths, $missing_paths);
      +  }

    Do we need two helper functions, where one does a single assertion and then calls the other? In other words, is there any harm in asserting "What will be upgraded?" every time we call assertUpgradePaths()?

    If the answers are "no", then I would like to add the assertion to assertUpgradePaths() and then rename it to assertReviewForm().

  2. Related: almost every time that assertUpgradePaths() is called, it looks like this:

     $available_paths = $this->getAvailablePaths();
     $missing_paths = $this->getMissingPaths();
     $this->assertUpgradePaths($session, $available_paths, $missing_paths);

    Can we make the two array arguments optional, using those methods as defaults? Maybe this change is out of scope for this issue, but if we do (1) then I think we can call it in scope.

  3.   diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
      @@ -260,4 +251,85 @@ protected function assertMigrationResults(array $expected_counts, $version) {
      +  /**
      +   * Helper to assert content on the Overview form.
      +   *
      +   * @param \Drupal\Tests\WebAssert $session
      +   *   The web-assert session.
      +   *
      +   * @throws \Behat\Mink\Exception\ExpectationException
      +   */
      +  protected function assertOverviewForm(WebAssert $session) {
      +    $session->responseContains("Upgrade a site by importing its files and the data from its database into a clean and empty new install of Drupal $this->destinationSiteVersion.");
      +  }
      +
      +  /**
      +   * Helper to assert content on the Overview form.
      +   *
      +   * @param \Drupal\Tests\WebAssert $session
      +   *   The web-assert session.
      +   *
      +   * @throws \Behat\Mink\Exception\ExpectationException
      +   */
      +  protected function assertIncrementalForm(WebAssert $session) {
      +    $session->pageTextContains("An upgrade has already been performed on this site. To perform a new migration, create a clean and empty new install of Drupal $this->destinationSiteVersion. Rollbacks are not yet supported through the user interface.");
      +  }

    The doc blocks are identical. The second function is called only once; like the first function, it is called immediately after $this->drupalGet('/upgrade');. The name of the second function is problematic, since it suggests that there is an Incremental form.

    I suggest that we solve all of these annoyances by adding an optional boolean parameter, perhaps $is_incremental, to the first of these functions and eliminate the second function. I think we can always test for "Upgrade a site …" and conditionally test for the second string.

    Is there a reason to use responseContains() instead of pageTextContains()? For HTML responses, they are equivalent, right?

  4.   +  /**
      +   * Helper method to assert the text on the 'Upgrade analysis report' page.
      ...
      +   */
      +  protected function assertReviewForm(WebAssert $session, array $available_paths, array $missing_paths) {

    Is there any reason to vary from the pattern of the other short descriptions?

  5.   +  protected function assertUpgrade($session, $version, array $entity_counts) {
      +    $session->pageTextContains(t('Congratulations, you upgraded Drupal!'));
      +    $this->assertMigrationResults($entity_counts, $version);
      +  }

    Again, do we need both methods? I searched for assertMigrationResults(), and it is not called except for here. Why not just add the assertion to that function?

benjifisher’s picture

Follow-up to #7.2: After applying the patch in #8, I still see the line

    $this->assertNotEmpty($entity_types, 'No entity types provided to \Drupal\Tests\migrate_drupal_ui\Functional\MigrateUpgradeTestBase::assertIdConflict()');

in MigrateUpgradeTestBase.

quietone’s picture

Status: Needs work » Needs review
FileSize
19.59 KB
25.99 KB

#10
1. Fixed
2. Yes, l let's do this.
3. Ah, there really is an Incremental form I have updated the summary line.
4. Oops. Fixed now.
5. Not really. Fixed.

#11. Should be fixed this time.

benjifisher’s picture

Title: Add assert helper methods to migrate_drupal_ui functional tests » Add helper methods to the migrate_drupal_ui functional tests
Issue summary: View changes

Thanks, the patch in #12 looks great! RTBC

I rewrote the issue summary using the standard template, in order to help the final review. The last couple of points might be considered out of scope; I made the issue title a little more generic in the hope that at least assertUserLogIn() will be considered in scope. If we want to avoid objections to the scope, we might preemptively revert the move of $destinationSiteVersion until we remove MigrateUpgradeExecuteTestBase.

benjifisher’s picture

Status: Needs review » Reviewed & tested by the community

Oops, I forgot to update the status.

quietone’s picture

FYI, According to http://grep.xnddx.ru/ there are no usages MigrateUpgradeExecuteTestBase in contrib and two for MigrateUpgradeTestBase, migrate_media and migrate_upgrade.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 12: 3143717-12.patch, failed testing. View results

benjifisher’s picture

Two unrelated tests are failing. (At least, I think they are unrelated.) I will ask the testbot to try again.

quietone’s picture

Status: Needs work » Reviewed & tested by the community

Tests passing again. Setting back to RTBC

quietone’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs reroll
quietone’s picture

Status: Needs work » Needs review
FileSize
4.5 KB
25.5 KB

Rerolled.

benjifisher’s picture

Status: Needs review » Needs work

Thanks for the reroll! I see just one problem:

    +++ b/core/modules/migrate_drupal_ui/tests/src/Functional/d6/NodeClassicTest.php
    @@ -82,23 +82,23 @@ public function testMigrateUpgradeExecute() {
         $this->drupalGet('/upgrade');
    +
         $session = $this->assertSession();
    -    $session->responseContains("Upgrade a site by importing its files and the data from its database into a clean and empty new install of Drupal $this->destinationSiteVersion.");
    +    $this->drupalGet('/upgrade');
    +    $this->assertOverviewForm($session);

The patch in #12 removed the first drupalGet() line. After the patch in #20, that function is called twice.

This reroll makes me think I was right to put off reviewing the other children of #2974445: [Meta] Refactor Migrate Drupal UI Functional tests until the first two are committed.

quietone’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
FileSize
717 bytes
25.54 KB

Thanks again. And yes, you were right to wait. Good planning.

benjifisher’s picture

Status: Needs review » Reviewed & tested by the community

Nice work. Back to RTBC.

quietone’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
1.78 KB
25.49 KB

Didn't know this needed a reroll.

Status: Needs review » Needs work

The last submitted patch, 24: 3143717-24.patch, failed testing. View results

quietone’s picture

Status: Needs work » Needs review
FileSize
2.66 KB
25.52 KB

Oh dear, bad reroll. I wasn't paying attention and I forgot that #3134300: Simplify ReviewForm::buildForm() and the resulting markup was in.

quietone’s picture

Issue tags: +Migrate UI
benjifisher’s picture

Status: Needs review » Reviewed & tested by the community

I compared (diff, not interdiff) the patches in #12 and #26. Aside from routine stuff (different line numbers and commit hashes, changes to context lines, etc.) the main difference was to change span to td in CSS selectors: moved from assertUpgradePaths() to assertReviewForm(). As you say, that change comes from #3134300: Simplify ReviewForm::buildForm() and the resulting markup.

I then re-reviewed the patch as a whole, looking for reroll problems like the one I pointed out in #21. To make the review of MigrateUpgradeTestBase easier, I moved assertReviewForm() before getSourceBasePath() so that I could compare it to assertUpgradePaths().

I did not remember why the assertions in assertReviewPage() were not added to one of the new helper functions, but I see that we already discussed one of them in #7.4, and I see the other pageTextNotContains() lines are still repeated in MigrateUpgradeExecuteTestBase.

Back to RTBC.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 26: 3143717-26.patch, failed testing. View results

quietone’s picture

Status: Needs work » Reviewed & tested by the community

There was a random test failure, retested and tests are passing. Back to RTBC.

alexpott’s picture

Issue summary: View changes
Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
    @@ -212,21 +175,101 @@ protected function assertIdConflict(WebAssert $session, array $entity_types) {
    +  protected function assertOverviewForm(WebAssert $session) {
    +    $session->responseContains("Upgrade a site by importing its files and the data from its database into a clean and empty new install of Drupal $this->destinationSiteVersion.");
    +  }
    ...
    +  protected function assertIncrementalForm(WebAssert $session) {
    +    $session->pageTextContains("An upgrade has already been performed on this site. To perform a new migration, create a clean and empty new install of Drupal $this->destinationSiteVersion. Rollbacks are not yet supported through the user interface.");
    +  }
    ...
    +  protected function assertCredentialForm(WebAssert $session) {
    +    $session->pageTextContains('Provide credentials for the database of the Drupal site you want to upgrade.');
    +    $session->fieldExists('mysql[host]');
    +  }
    

    I'm not convinced this tiny assert methods are a good idea. The abstraction make tests harder to read, an extra thing to know about, an extra thing to maintain. DRY is not always correct - especially in tests. I guess it makes the UI easier to update BUT find/replace does exist. Plus as said below i really don't think we should be passing in $session if we do do this.

  2. +++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeTestBase.php
    @@ -212,21 +175,101 @@ protected function assertIdConflict(WebAssert $session, array $entity_types) {
    -  protected function assertMigrationResults(array $expected_counts, $version) {
    -    // Have to reset all the statics after migration to ensure entities are
    -    // loadable.
    +  protected function assertUpgrade($session, $version, array $entity_counts) {
    +    $session->pageTextContains(t('Congratulations, you upgraded Drupal!'));
    

    I don't think we should be passing $session into these methods because:

    • Other asserts do not do this.
    • This is a testbase call and call $this->assertSession() just fine.
    • If we do do this (let's not) - this one needs a type hint.

    Yes other asserts added here do pass in $session already but two wrongs...

quietone’s picture

Status: Needs work » Needs review
FileSize
14.42 KB
17.25 KB

31.1 Removed the assert helpers, assertOverviewForm, assertIncrementalForm, and assertCredentialForm. For me, having these makes the test easier to read and work with but I am not going to argue the point.

31.2 Removed passing $session.

Status: Needs review » Needs work

The last submitted patch, 32: 3143717-32.patch, failed testing. View results

quietone’s picture

Status: Needs work » Needs review
FileSize
1.12 KB
17.26 KB

I had a feeling I missed something.

quietone’s picture

Issue summary: View changes

Update to IS to reflect changes due to #31.

benjifisher’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community

(facepalm) I was reviewing the patch from #32 and explaining the difference between ?: and ??. The patch in #34 fixes that. I am glad that the testbot caught the difference, too: a sign that our test coverage is pretty good!

I compared the patch in #34 to the one in #26. (Almost true.) It makes the changes requested in #31. As for whether or not the 1- or 2-line helper methods are useful, I will just check that they work. I defer to both @alexpott and @quietone on general testing strategy.

I also did a quick review of the patch in #34 as a whole. Most of it looks familiar. ;)

Looking at the changes to the issue summary, I am reminded that it already mentions some of the points that worried me a bit in #28. I also see that it now mentions "helper classes" instead of "helper functions". If that mistake were in the patch, I would have to send the issue back to NW, but I can fix the issue summary myself .

Back to RTBC.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed b4dbfc1 and pushed to 9.1.x. Thanks!

  • alexpott committed b4dbfc1 on 9.1.x
    Issue #3143717 by quietone, benjifisher, alexpott: Add helper methods to...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.