custom_elements-8.x-2.x-dev/tests/src/Kernel/LayoutBuilderIntegrationTest.php

tests/src/Kernel/LayoutBuilderIntegrationTest.php
<?php

declare(strict_types=1);

namespace Drupal\Tests\custom_elements\Kernel;

use Drupal\custom_elements\CustomElement;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\KernelTests\KernelTestBase;
use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage;
use Drupal\layout_builder\Section;
use Drupal\layout_builder\SectionComponent;
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
use Drupal\Tests\node\Traits\NodeCreationTrait;

/**
 * Tests Custom Elements Layout Builder integration via entity_ce_display.
 *
 * @group custom_elements
 */
class LayoutBuilderIntegrationTest extends KernelTestBase {

  use ContentTypeCreationTrait;
  use NodeCreationTrait;

  /**
   * {@inheritdoc}
   */
  protected $strictConfigSchema = FALSE;

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'system',
    'user',
    'field',
    'node',
    'text',
    'filter',
    'options',
    'image',
    'file',
    'media',
    'link',
    'layout_discovery',
    'layout_builder',
    'block',
    'block_content',
    'custom_elements',
  ];

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();

    $this->installEntitySchema('user');
    $this->installEntitySchema('media');
    $this->installEntitySchema('node');
    $this->installEntitySchema('block_content');
    $this->installEntitySchema('entity_ce_display');
    $this->installSchema('node', ['node_access']);
    $this->installSchema('layout_builder', ['inline_block_usage']);
    $this->installConfig(['system', 'field', 'node', 'filter', 'layout_builder', 'block', 'custom_elements']);

    // Mark layout_builder as installed to fix entity type alter hook
    // In kernel tests, modules are marked as SCHEMA_UNINSTALLED (-1) by
    // default. This causes custom_elements_entity_type_alter() to skip
    // changing the entity class because it thinks layout_builder is being
    // installed.
    \Drupal::service('update.update_hook_registry')->setInstalledVersion('layout_builder', 8000);

    // Create a content type.
    $this->createContentType(['type' => 'article', 'name' => 'Article']);

    // Force entity type manager to rebuild after marking layout_builder as
    // installed.
    \Drupal::entityTypeManager()->clearCachedDefinitions();

    // Enable Layout Builder for the article content type.
    $this->enableLayoutBuilderForContentType('article');
  }

  /**
   * Enables Layout Builder for a given content type.
   */
  protected function enableLayoutBuilderForContentType(string $content_type): void {
    // Delete existing view display if it exists.
    $view_display = EntityViewDisplay::load("node.{$content_type}.default");
    if ($view_display) {
      $view_display->delete();
    }

    // Force entity type manager to clear cached definitions again.
    \Drupal::entityTypeManager()->clearCachedDefinitions();

    // Create new view display with the correct class.
    $view_display = EntityViewDisplay::create([
      'targetEntityType' => 'node',
      'bundle' => $content_type,
      'mode' => 'default',
      'status' => TRUE,
    ]);

    // Enable Layout Builder.
    $view_display->enableLayoutBuilder()
      ->setOverridable()
      ->save();
  }

  /**
   * Creates a layout with sections and components.
   */
  protected function createLayoutWithSections(): array {
    // Create a two-column layout section.
    $section = new Section('layout_twocol_section');

    $component1 = new SectionComponent(\Drupal::service('uuid')->generate(), 'first', [
      'id' => 'system_powered_by_block',
      'label' => 'Powered by Drupal',
      'provider' => 'system',
      'label_display' => 'visible',
    ]);
    $section->appendComponent($component1);

    $component2 = new SectionComponent(\Drupal::service('uuid')->generate(), 'second', [
      'id' => 'system_branding_block',
      'label' => 'Site branding',
      'provider' => 'system',
      'label_display' => 'visible',
    ]);
    $section->appendComponent($component2);

    return [$section];
  }

  /**
   * Tests EntityCeDisplay with Layout Builder integration.
   *
   * This test verifies that when an EntityCeDisplay is configured with
   * useLayoutBuilder = TRUE, the Custom Elements generator properly
   * converts Layout Builder sections into drupal-layout custom elements
   * with nested custom elements for the block content.
   */
  public function testEntityCeDisplayWithLayoutBuilder(): void {
    // Create EntityCeDisplay with Layout Builder support enabled.
    $entity_ce_display = \Drupal::entityTypeManager()
      ->getStorage('entity_ce_display')
      ->create([
        'id' => 'node.article.default',
        'targetEntityType' => 'node',
        'bundle' => 'article',
        'mode' => 'default',
        'customElementName' => 'drupal-article',
        'useLayoutBuilder' => TRUE,
        'status' => TRUE,
      ]);
    $entity_ce_display->save();

    // Create a node with Layout Builder sections.
    $node = $this->createNode([
      'type' => 'article',
      'title' => 'Layout Builder CE Display Test',
      'body' => [
        'value' => 'Testing Layout Builder with Custom Elements Display.',
        'format' => 'plain_text',
      ],
    ]);

    // Add layout overrides with two-column layout.
    $sections = $this->createLayoutWithSections();
    $layout_builder_field = $node->get(OverridesSectionStorage::FIELD_NAME);
    foreach ($sections as $section) {
      $layout_builder_field->appendSection($section);
    }
    $node->save();

    // Use the actual Custom Elements generator to render the entity via
    // EntityCeDisplay.
    $generator = \Drupal::service('custom_elements.generator');
    $custom_element = $generator->generate($node, 'default');

    // Assert that we have a custom element with the correct tag.
    $this->assertInstanceOf(CustomElement::class, $custom_element);
    $this->assertEquals('drupal-article', $custom_element->getTag());

    $sections_slot = $custom_element->getSlot('sections', 0);
    $this->assertNotNull($sections_slot, 'Custom element should have a sections slot');
    $this->assertArrayHasKey('content', $sections_slot, 'Sections slot should have content');

    $layout_element = $sections_slot['content'];
    $this->assertInstanceOf(CustomElement::class, $layout_element);
    $this->assertStringStartsWith('drupal-layout', $layout_element->getTag());

    // Access layout regions using getSlot() with hard-coded indices
    // First region contains the first block (system_powered_by_block)
    $first_region_slot = $layout_element->getSlot('first', 0);
    $this->assertNotNull($first_region_slot, 'Layout should have a first region at index 0');
    $this->assertArrayHasKey('content', $first_region_slot, 'First region slot should have content');

    $first_region_content = $first_region_slot['content'];
    $this->assertInstanceOf(CustomElement::class, $first_region_content,
      'First region should contain a custom element');
    $this->assertEquals('drupal-markup', $first_region_content->getTag(),
      'First region should contain a drupal-markup element with block content');

    // Second region contains the second block (system_branding_block)
    $second_region_slot = $layout_element->getSlot('second', 0);
    $this->assertNotNull($second_region_slot, 'Layout should have a second region at index 0');
    $this->assertArrayHasKey('content', $second_region_slot, 'Second region slot should have content');

    $second_region_content = $second_region_slot['content'];
    $this->assertInstanceOf(CustomElement::class, $second_region_content,
      'Second region should contain a custom element');
    $this->assertEquals('drupal-markup', $second_region_content->getTag(),
      'Second region should contain a drupal-markup element with block content');

    // Verify both regions have actual block content.
    $this->assertNotEmpty($first_region_content->getSlots(), 'First region element should have content slots');
    $this->assertNotEmpty($second_region_content->getSlots(), 'Second region element should have content slots');
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc