StandardTestTrait.php

Same filename in other branches
  1. 11.x core/profiles/standard/tests/src/Traits/StandardTestTrait.php

Namespace

Drupal\Tests\standard\Traits

File

core/profiles/standard/tests/src/Traits/StandardTestTrait.php

View source
<?php

declare (strict_types=1);
namespace Drupal\Tests\standard\Traits;

use Drupal\ckeditor5\Plugin\Editor\CKEditor5;
use Drupal\Component\Utility\Html;
use Drupal\contact\Entity\ContactForm;
use Drupal\Core\Url;
use Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber;
use Drupal\editor\Entity\Editor;
use Drupal\filter\Entity\FilterFormat;
use Drupal\image\Entity\ImageStyle;
use Drupal\media\Entity\MediaType;
use Drupal\media\Plugin\media\Source\Image;
use Drupal\Tests\RequirementsPageTrait;
use Drupal\Tests\SchemaCheckTestTrait;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
use Symfony\Component\Validator\ConstraintViolation;

/**
 * Provides a test method to test the Standard installation profile or recipe.
 */
trait StandardTestTrait {
    use SchemaCheckTestTrait;
    use RequirementsPageTrait;
    
    /**
     * The admin user.
     *
     * @var \Drupal\user\UserInterface
     */
    protected $adminUser;
    
    /**
     * Tests Standard installation profile or recipe.
     */
    public function testStandard() : void {
        $this->drupalGet('');
        $this->assertSession()
            ->pageTextContains('Powered by Drupal');
        $this->assertSession()
            ->pageTextContains('Congratulations and welcome to the Drupal community.');
        // Test anonymous user can access 'Main navigation' block.
        $this->adminUser = $this->drupalCreateUser([
            'administer blocks',
            'administer block content',
            'post comments',
            'skip comment approval',
            'create article content',
            'create page content',
        ]);
        $this->drupalLogin($this->adminUser);
        // Configure the block.
        $this->drupalGet('admin/structure/block/add/system_menu_block:main/olivero');
        $this->submitForm([
            'region' => 'sidebar',
            'id' => 'main_navigation',
        ], 'Save block');
        // Verify admin user can see the block.
        $this->drupalGet('');
        $this->assertSession()
            ->pageTextContains('Main navigation');
        // Verify we have role = complementary on help_block blocks.
        $this->drupalGet('admin/structure/block');
        $this->assertSession()
            ->elementAttributeContains('xpath', "//div[@id='block-olivero-help']", 'role', 'complementary');
        // Verify anonymous user can see the block.
        $this->drupalLogout();
        $this->assertSession()
            ->pageTextContains('Main navigation');
        // Ensure comments don't show in the front page RSS feed.
        // Create an article.
        $this->drupalCreateNode([
            'type' => 'article',
            'title' => 'Foobar',
            'promote' => 1,
            'status' => 1,
            'body' => [
                [
                    'value' => 'Then she picked out two somebodies,<br />Sally and me',
                    'format' => 'basic_html',
                ],
            ],
        ]);
        // Add a comment.
        $this->drupalLogin($this->adminUser);
        $this->drupalGet('node/1');
        // Verify that a line break is present.
        $this->assertSession()
            ->responseContains('Then she picked out two somebodies,<br>Sally and me');
        $this->submitForm([
            'subject[0][value]' => 'Bar foo',
            'comment_body[0][value]' => 'Then she picked out two somebodies, Sally and me',
        ], 'Save');
        // Fetch the feed.
        $this->drupalGet('rss.xml');
        $this->assertSession()
            ->responseContains('Foobar');
        $this->assertSession()
            ->responseNotContains('Then she picked out two somebodies, Sally and me');
        // Ensure block body exists.
        $this->drupalGet('block/add');
        $this->assertSession()
            ->fieldExists('body[0][value]');
        // Now we have all configuration imported, test all of them for schema
        // conformance. Ensures all imported default configuration is valid when
        // standard 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()))));
        }
        // Ensure that configuration from the Standard profile is not reused when
        // enabling a module again since it contains configuration that can not be
        // installed. For example, editor.editor.basic_html is editor configuration
        // that depends on the CKEditor 5 module. The CKEditor 5 module can not be
        // installed before the editor module since it depends on the editor module.
        // The installer does not have this limitation since it ensures that all of
        // the install profiles dependencies are installed before creating the
        // editor configuration.
        foreach (FilterFormat::loadMultiple() as $filter) {
            // Ensure that editor can be uninstalled by removing use in filter
            // formats. It is necessary to prime the filter collection before removing
            // the filter.
            $filter->filters();
            $filter->removeFilter('editor_file_reference');
            $filter->save();
        }
        \Drupal::service('module_installer')->uninstall([
            'editor',
            'ckeditor5',
        ]);
        $this->rebuildContainer();
        \Drupal::service('module_installer')->install([
            'editor',
        ]);
        
        /** @var \Drupal\contact\ContactFormInterface $contact_form */
        $contact_form = ContactForm::load('feedback');
        $recipients = $contact_form->getRecipients();
        $this->assertEquals([
            'simpletest@example.com',
        ], $recipients);
        $role = Role::create([
            'id' => 'admin_theme',
            'label' => 'Admin theme',
        ]);
        $role->grantPermission('view the administration theme');
        $role->save();
        $this->adminUser
            ->addRole($role->id())
            ->save();
        $this->drupalGet('node/add');
        $this->assertSession()
            ->statusCodeEquals(200);
        // Ensure that there are no pending updates after installation.
        $this->drupalLogin($this->rootUser);
        $this->drupalGet('update.php/selection');
        $this->updateRequirementsProblem();
        $this->drupalGet('update.php/selection');
        $this->assertSession()
            ->pageTextContains('No pending updates.');
        // Ensure that there are no pending entity updates after installation.
        $this->assertFalse($this->container
            ->get('entity.definition_update_manager')
            ->needsUpdates(), 'After installation, entity schema is up to date.');
        // Make sure the optional image styles are not installed.
        $this->drupalGet('admin/config/media/image-styles');
        $this->assertSession()
            ->pageTextNotContains('Max 325x325');
        $this->assertSession()
            ->pageTextNotContains('Max 650x650');
        $this->assertSession()
            ->pageTextNotContains('Max 1300x1300');
        $this->assertSession()
            ->pageTextNotContains('Max 2600x2600');
        // Make sure the optional image styles are installed after enabling
        // the responsive_image module.
        $this->installResponsiveImage();
        $this->drupalGet('admin/config/media/image-styles');
        $this->assertSession()
            ->pageTextContains('Max 325x325');
        $this->assertSession()
            ->pageTextContains('Max 650x650');
        $this->assertSession()
            ->pageTextContains('Max 1300x1300');
        $this->assertSession()
            ->pageTextContains('Max 2600x2600');
        // Make sure all image styles has webp conversion as last effect.
        foreach (ImageStyle::loadMultiple() as $style) {
            $effects = $style->getEffects()
                ->getInstanceIds();
            $last = $style->getEffects()
                ->get(end($effects));
            $this->assertSame('image_convert', $last->getConfiguration()['id']);
            $this->assertSame('webp', $last->getConfiguration()['data']['extension']);
        }
        // Verify certain routes' responses are cacheable by Dynamic Page Cache, to
        // ensure these responses are very fast for authenticated users.
        $this->drupalLogin($this->adminUser);
        $url = Url::fromRoute('contact.site_page');
        $this->drupalGet($url);
        // Verify that site-wide contact page cannot be cached by Dynamic Page
        // Cache.
        $this->assertSession()
            ->responseHeaderEquals(DynamicPageCacheSubscriber::HEADER, 'UNCACHEABLE');
        $url = Url::fromRoute('<front>');
        $this->drupalGet($url);
        $this->drupalGet($url);
        // Verify that frontpage is cached by Dynamic Page Cache.
        $this->assertSession()
            ->responseHeaderEquals(DynamicPageCacheSubscriber::HEADER, 'HIT');
        $url = Url::fromRoute('entity.node.canonical', [
            'node' => 1,
        ]);
        $this->drupalGet($url);
        $this->drupalGet($url);
        // Verify that full node page is cached by Dynamic Page Cache.
        $this->assertSession()
            ->responseHeaderEquals(DynamicPageCacheSubscriber::HEADER, 'HIT');
        $url = Url::fromRoute('entity.user.canonical', [
            'user' => 1,
        ]);
        $this->drupalGet($url);
        $this->drupalGet($url);
        // Verify that user profile page is cached by Dynamic Page Cache.
        $this->assertSession()
            ->responseHeaderEquals(DynamicPageCacheSubscriber::HEADER, 'HIT');
        // Make sure the editorial workflow is installed after enabling the
        // content_moderation module.
        \Drupal::service('module_installer')->install([
            'content_moderation',
        ]);
        $role = Role::create([
            'id' => 'admin_workflows',
            'label' => 'Admin workflow',
        ]);
        $role->grantPermission('administer workflows');
        $role->save();
        $this->adminUser
            ->addRole($role->id())
            ->save();
        $this->rebuildContainer();
        $this->drupalGet('admin/config/workflow/workflows/manage/editorial');
        $this->assertSession()
            ->pageTextContains('Draft');
        $this->assertSession()
            ->pageTextContains('Published');
        $this->assertSession()
            ->pageTextContains('Archived');
        $this->assertSession()
            ->pageTextContains('Create New Draft');
        $this->assertSession()
            ->pageTextContains('Publish');
        $this->assertSession()
            ->pageTextContains('Archive');
        $this->assertSession()
            ->pageTextContains('Restore to Draft');
        $this->assertSession()
            ->pageTextContains('Restore');
        \Drupal::service('module_installer')->install([
            'media',
        ]);
        $role = Role::create([
            'id' => 'admin_media',
            'label' => 'Admin media',
        ]);
        $role->grantPermission('administer media');
        $role->grantPermission('administer media display');
        $role->save();
        $this->adminUser
            ->addRole($role->id())
            ->save();
        $assert_session = $this->assertSession();
        $page = $this->getSession()
            ->getPage();
        
        /** @var \Drupal\media\Entity\MediaType $media_type */
        foreach (MediaType::loadMultiple() as $media_type) {
            $media_type_machine_name = $media_type->id();
            $this->drupalGet('media/add/' . $media_type_machine_name);
            // Get the form element, and its HTML representation.
            $form_selector = '#media-' . Html::cleanCssIdentifier($media_type_machine_name) . '-add-form';
            $form = $assert_session->elementExists('css', $form_selector);
            $form_html = $form->getOuterHtml();
            // The name field should be hidden.
            $assert_session->fieldNotExists('Name', $form);
            // The source field should be shown before the vertical tabs.
            $source_field_label = $media_type->getSource()
                ->getSourceFieldDefinition($media_type)
                ->getLabel();
            $test_source_field = $assert_session->elementExists('xpath', "//*[contains(text(), '{$source_field_label}')]", $form)
                ->getOuterHtml();
            $vertical_tabs = $assert_session->elementExists('css', '.js-form-type-vertical-tabs', $form)
                ->getOuterHtml();
            $this->assertGreaterThan(strpos($form_html, $test_source_field), strpos($form_html, $vertical_tabs));
            // The "Published" checkbox should be the last element.
            $date_field = $assert_session->fieldExists('Date', $form)
                ->getOuterHtml();
            $published_checkbox = $assert_session->fieldExists('Published', $form)
                ->getOuterHtml();
            $this->assertGreaterThan(strpos($form_html, $date_field), strpos($form_html, $published_checkbox));
            if (is_a($media_type->getSource(), Image::class, TRUE)) {
                // Assert the default entity view display is configured with an image
                // style.
                $this->drupalGet('/admin/structure/media/manage/' . $media_type->id() . '/display');
                $assert_session->fieldValueEquals('fields[field_media_image][type]', 'image');
                $assert_session->elementTextContains('css', 'tr[data-drupal-selector="edit-fields-field-media-image"]', 'Image style: Large (480×480)');
                // By default for media types with an image source, only the image
                // component should be enabled.
                $assert_session->elementsCount('css', 'input[name$="_settings_edit"]', 1);
            }
        }
        // Tests that user 1 does not have an all-access pass.
        $this->drupalLogin($this->rootUser);
        $this->drupalGet('admin');
        $this->assertSession()
            ->statusCodeEquals(200);
        User::load(1)->removeRole('administrator')
            ->save();
        // Clear caches so change take effect in system under test.
        $this->rebuildAll();
        $this->drupalGet('admin');
        $this->assertSession()
            ->statusCodeEquals(403);
    }
    
    /**
     * Installs the responsive image module.
     */
    protected function installResponsiveImage() : void {
        // Install responsive_image module.
        \Drupal::service('module_installer')->install([
            'responsive_image',
        ]);
        $this->rebuildContainer();
    }

}

Traits

Title Deprecated Summary
StandardTestTrait Provides a test method to test the Standard installation profile or recipe.

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