DemoUmamiProfileTest.php

Same filename and directory in other branches
  1. 9 core/profiles/demo_umami/tests/src/Functional/DemoUmamiProfileTest.php
  2. 8.9.x core/profiles/demo_umami/tests/src/Functional/DemoUmamiProfileTest.php
  3. 11.x core/profiles/demo_umami/tests/src/Functional/DemoUmamiProfileTest.php

Namespace

Drupal\Tests\demo_umami\Functional

File

core/profiles/demo_umami/tests/src/Functional/DemoUmamiProfileTest.php

View source
<?php

declare (strict_types=1);
namespace Drupal\Tests\demo_umami\Functional;

use Drupal\ckeditor5\Plugin\Editor\CKEditor5;
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Config\InstallStorage;
use Drupal\Core\Config\StorageInterface;
use Drupal\editor\Entity\Editor;
use Drupal\KernelTests\AssertConfigTrait;
use Drupal\Tests\BrowserTestBase;
use Drupal\Core\Session\AccountInterface;
use Drupal\Tests\SchemaCheckTestTrait;
use Symfony\Component\Validator\ConstraintViolation;

/**
 * Tests demo_umami profile.
 *
 * @group demo_umami
 * @group #slow
 */
class DemoUmamiProfileTest extends BrowserTestBase {
  use AssertConfigTrait;
  use SchemaCheckTestTrait;
  
  /**
   * {@inheritdoc}
   */
  protected function installParameters() {
    $parameters = parent::installParameters();
    $parameters['forms']['install_configure_form']['site_mail'] = 'admin@example.com';
    return $parameters;
  }
  
  /**
   * {@inheritdoc}
   */
  protected $profile = 'demo_umami';
  
  /**
   * Tests various capabilities of the demo profile.
   */
  public function testDemoFeatures() : void {
    // This test coverage is organized into separate protected methods rather
    // than individual test methods to avoid having to reinstall Umami for
    // a handful of assertions each.
    $this->testUser();
    $this->testWarningsOnStatusPage();
    $this->testAppearance();
    $this->testDemonstrationWarningMessage();
    $this->testConfig();
    $this->testEditNodesByAdmin();
  }
  
  /**
   * Tests demo_umami profile warnings shown on Status Page.
   */
  protected function testWarningsOnStatusPage() {
    $account = $this->drupalCreateUser([
      'administer site configuration',
    ]);
    $this->drupalLogin($account);
    // Check the requirements warning for using an experimental profile.
    $this->drupalGet('admin/reports/status');
    $this->assertSession()
      ->pageTextContains('Experimental profiles are provided for testing purposes only. Use at your own risk. To start building a new site, reinstall Drupal and choose a non-experimental profile.');
  }
  
  /**
   * Tests the profile supplied configuration is the same after installation.
   */
  protected function testConfig() : void {
    // Just connect directly to the config table so we don't need to worry about
    // the cache layer.
    $active_config_storage = $this->container
      ->get('config.storage');
    $default_config_storage = new FileStorage($this->container
      ->get('extension.list.profile')
      ->getPath('demo_umami') . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY, InstallStorage::DEFAULT_COLLECTION);
    $this->assertDefaultConfig($default_config_storage, $active_config_storage);
    $default_config_storage = new FileStorage($this->container
      ->get('extension.list.profile')
      ->getPath('demo_umami') . '/' . InstallStorage::CONFIG_OPTIONAL_DIRECTORY, InstallStorage::DEFAULT_COLLECTION);
    $this->assertDefaultConfig($default_config_storage, $active_config_storage);
    // Now we have all configuration imported, test all of them for schema
    // conformance. Ensures all imported default configuration is valid when
    // Demo Umami profile modules are enabled.
    $names = $this->container
      ->get('config.storage')
      ->listAll();
    /** @var \Drupal\Core\Config\TypedConfigManagerInterface $typed_config */
    $typed_config = $this->container
      ->get('config.typed');
    foreach ($names as $name) {
      $config = $this->config($name);
      $this->assertConfigSchema($typed_config, $name, $config->get());
    }
    // Validate all configuration.
    // @todo Generalize in https://www.drupal.org/project/drupal/issues/2164373
    foreach (Editor::loadMultiple() as $editor) {
      // Currently only text editors using CKEditor 5 can be validated.
      if ($editor->getEditor() !== 'ckeditor5') {
        continue;
      }
      $this->assertSame([], array_map(function (ConstraintViolation $v) {
        return (string) $v->getMessage();
      }, iterator_to_array(CKEditor5::validatePair($editor, $editor->getFilterFormat()))));
    }
  }
  
  /**
   * Asserts that the default configuration matches active configuration.
   *
   * @param \Drupal\Core\Config\StorageInterface $default_config_storage
   *   The default configuration storage to check.
   * @param \Drupal\Core\Config\StorageInterface $active_config_storage
   *   The active configuration storage.
   */
  protected function assertDefaultConfig(StorageInterface $default_config_storage, StorageInterface $active_config_storage) : void {
    /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
    $config_manager = $this->container
      ->get('config.manager');
    foreach ($default_config_storage->listAll() as $config_name) {
      if ($active_config_storage->exists($config_name)) {
        $result = $config_manager->diff($default_config_storage, $active_config_storage, $config_name);
        $this->assertConfigDiff($result, $config_name, [
          // The filter.format.*:roles key is a special install key.
'filter.format.basic_html' => [
            'roles:',
            '  - authenticated',
          ],
          'filter.format.full_html' => [
            'roles:',
            '  - administrator',
          ],
          'filter.format.restricted_html' => [
            'roles:',
            '  - anonymous',
          ],
          // The system.site config is overwritten during tests by
          // FunctionalTestSetupTrait::installParameters().
'system.site' => [
            'uuid:',
            'name:',
            'mail:',
          ],
        ]);
      }
      else {
        $this->fail("{$config_name} has not been installed");
      }
    }
  }
  
  /**
   * Tests that the users can log in with the admin password entered at install.
   */
  protected function testUser() {
    $password = $this->rootUser->pass_raw;
    $ids = \Drupal::entityQuery('user')->accessCheck(FALSE)
      ->condition('roles', [
      'author',
      'editor',
    ], 'IN')
      ->execute();
    $users = \Drupal::entityTypeManager()->getStorage('user')
      ->loadMultiple($ids);
    foreach ($users as $user) {
      $this->drupalLoginWithPassword($user, $password);
    }
  }
  
  /**
   * Tests the successful editing of nodes by admin.
   */
  protected function testEditNodesByAdmin() : void {
    $permissions = [
      'administer nodes',
      'edit any recipe content',
      'use editorial transition create_new_draft',
    ];
    $account = $this->drupalCreateUser($permissions);
    $this->drupalLogin($account);
    $webassert = $this->assertSession();
    // Check that admin is able to edit the node.
    $nodes = $this->container
      ->get('entity_type.manager')
      ->getStorage('node')
      ->loadByProperties([
      'title' => 'Deep mediterranean quiche',
    ]);
    $node = reset($nodes);
    $this->drupalGet($node->toUrl('edit-form'));
    $webassert->statusCodeEquals(200);
    $this->submitForm([], 'Preview');
    $webassert->statusCodeEquals(200);
    $this->assertSession()
      ->elementsCount('css', 'h1', 1);
    $this->clickLink('Back to content editing');
    $this->submitForm([], "Save");
    $webassert->pageTextContains('Recipe Deep mediterranean quiche has been updated.');
  }
  
  /**
   * Tests that the Umami theme is available on the Appearance page.
   */
  protected function testAppearance() {
    $account = $this->drupalCreateUser([
      'administer themes',
    ]);
    $this->drupalLogin($account);
    $webassert = $this->assertSession();
    $this->drupalGet('admin/appearance');
    $webassert->pageTextContains('Umami');
  }
  
  /**
   * Tests that the toolbar warning only appears on the admin pages.
   */
  protected function testDemonstrationWarningMessage() {
    $permissions = [
      'access content overview',
      'access toolbar',
      'administer nodes',
      'edit any recipe content',
      'create recipe content',
      'use editorial transition create_new_draft',
    ];
    $account = $this->drupalCreateUser($permissions);
    $this->drupalLogin($account);
    $web_assert = $this->assertSession();
    $nodes = $this->container
      ->get('entity_type.manager')
      ->getStorage('node')
      ->loadByProperties([
      'title' => 'Deep mediterranean quiche',
    ]);
    /** @var \Drupal\node\Entity\Node $recipe_node */
    $recipe_node = reset($nodes);
    // Check when editing a node, the warning is visible.
    $this->drupalGet($recipe_node->toUrl('edit-form'));
    $web_assert->statusCodeEquals(200);
    $web_assert->pageTextContains('This site is intended for demonstration purposes.');
    // Check when adding a node, the warning is visible.
    $this->drupalGet('node/add/recipe');
    $web_assert->statusCodeEquals(200);
    $web_assert->pageTextContains('This site is intended for demonstration purposes.');
    // Check when looking at admin/content, the warning is visible.
    $this->drupalGet('admin/content');
    $web_assert->statusCodeEquals(200);
    $web_assert->pageTextContains('This site is intended for demonstration purposes.');
    // Check when viewing a node, the warning is not visible.
    $this->drupalGet($recipe_node->toUrl());
    $web_assert->statusCodeEquals(200);
    $web_assert->pageTextNotContains('This site is intended for demonstration purposes.');
    // Check when viewing the homepage, the warning is not visible.
    $this->drupalGet('<front>');
    $web_assert->statusCodeEquals(200);
    $web_assert->pageTextNotContains('This site is intended for demonstration purposes.');
  }
  
  /**
   * Logs in a user using the Mink controlled browser using a password.
   *
   * If a user is already logged in, then the current user is logged out before
   * logging in the specified user.
   *
   * Note that neither the current user nor the passed-in user object is
   * populated with data of the logged in user. If you need full access to the
   * user object after logging in, it must be updated manually. If you also need
   * access to the plain-text password of the user (set by drupalCreateUser()),
   * e.g. to log in the same user again, then it must be re-assigned manually.
   * For example:
   * @code
   *   // Create a user.
   *   $account = $this->drupalCreateUser([]);
   *   $this->drupalLogin($account);
   *   // Load real user object.
   *   $pass_raw = $account->passRaw;
   *   $account = User::load($account->id());
   *   $account->passRaw = $pass_raw;
   * @endcode
   *
   * @param \Drupal\Core\Session\AccountInterface $account
   *   User object representing the user to log in.
   * @param string $password
   *   The password to authenticate the user with.
   *
   * @see drupalCreateUser()
   */
  protected function drupalLoginWithPassword(AccountInterface $account, $password) {
    if ($this->loggedInUser) {
      $this->drupalLogout();
    }
    $this->drupalGet('user/login');
    $this->submitForm([
      'name' => $account->getAccountName(),
      'pass' => $password,
    ], 'Log in');
    // @see ::drupalUserIsLoggedIn()
    $account->sessionId = $this->getSession()
      ->getCookie(\Drupal::service('session_configuration')->getOptions(\Drupal::request())['name']);
    $this->assertTrue($this->drupalUserIsLoggedIn($account), "User {$account->getAccountName()} successfully logged in.");
    $this->loggedInUser = $account;
    $this->container
      ->get('current_user')
      ->setAccount($account);
  }

}

Classes

Title Deprecated Summary
DemoUmamiProfileTest Tests demo_umami profile.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.