utilikit-1.0.0/tests/src/Kernel/UtilikitEntitySaveTest.php

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

declare(strict_types=1);

namespace Drupal\Tests\utilikit\Kernel;

use Drupal\KernelTests\KernelTestBase;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\block_content\Entity\BlockContent;
use Drupal\block_content\Entity\BlockContentType;
use Drupal\paragraphs\Entity\Paragraph;
use Drupal\paragraphs\Entity\ParagraphsType;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\utilikit\Service\UtilikitConstants;

/**
 * Tests entity save hooks and CSS auto-update functionality.
 *
 * @group utilikit
 */
class UtilikitEntitySaveTest extends KernelTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'system',
    'user',
    'node',
    'field',
    'text',
    'filter',
    'block_content',
    'paragraphs',
    'entity_reference_revisions',
    'file',
    'utilikit',
  ];

  /**
   * The UtiliKit service provider.
   *
   * @var \Drupal\utilikit\Service\UtilikitServiceProvider
   */
  protected $serviceProvider;

  /**
   * The state service.
   *
   * @var \Drupal\Core\State\StateInterface
   */
  protected $state;

  /**
   * The config factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * The lock service.
   *
   * @var \Drupal\Core\Lock\LockBackendInterface
   */
  protected $lock;

  /**
   * The queue factory.
   *
   * @var \Drupal\Core\Queue\QueueFactory
   */
  protected $queueFactory;

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

    // Install schemas.
    $this->installEntitySchema('node');
    $this->installEntitySchema('block_content');
    $this->installEntitySchema('paragraph');
    $this->installEntitySchema('user');
    $this->installSchema('node', ['node_access']);
    $this->installConfig(['node', 'filter', 'utilikit']);

    // Get services.
    $this->serviceProvider = $this->container->get('utilikit.service_provider');
    $this->state = $this->container->get('state');
    $this->configFactory = $this->container->get('config.factory');
    $this->lock = $this->container->get('lock');
    $this->queueFactory = $this->container->get('queue');

    // Create content types.
    $this->createContentTypes();

    // Set up default configuration.
    $config = $this->configFactory->getEditable('utilikit.settings');
    $config->set('rendering_mode', 'static');
    $config->save();
  }

  /**
   * Creates necessary content types and fields.
   */
  protected function createContentTypes() {
    // Create node type.
    NodeType::create([
      'type' => 'article',
      'name' => 'Article',
    ])->save();

    // Add body field to node.
    $this->createBodyField('node', 'article');

    // Create block content type.
    BlockContentType::create([
      'id' => 'basic',
      'label' => 'Basic block',
    ])->save();

    // Add body field to block.
    $this->createBodyField('block_content', 'basic');

    // Create paragraph type.
    ParagraphsType::create([
      'id' => 'text',
      'label' => 'Text paragraph',
    ])->save();

    // Add text field to paragraph.
    $this->createBodyField('paragraph', 'text', 'field_text');
  }

  /**
   * Creates a body/text field for an entity type.
   */
  protected function createBodyField($entity_type, $bundle, $field_name = 'body') {
    // Create field storage if it doesn't exist.
    if (!FieldStorageConfig::loadByName($entity_type, $field_name)) {
      FieldStorageConfig::create([
        'field_name' => $field_name,
        'entity_type' => $entity_type,
        'type' => 'text_with_summary',
      ])->save();
    }

    // Create field instance.
    if (!FieldConfig::loadByName($entity_type, $bundle, $field_name)) {
      FieldConfig::create([
        'field_name' => $field_name,
        'entity_type' => $entity_type,
        'bundle' => $bundle,
        'label' => 'Body',
      ])->save();
    }
  }

  /**
   * Tests node save with auto-update enabled.
   */
  public function testNodeSaveWithAutoUpdate() {
    // Enable auto-update for nodes.
    $config = $this->configFactory->getEditable('utilikit.settings');
    $config->set('update_on_node_save', TRUE);
    $config->save();

    // Clear any existing classes.
    $this->state->delete(UtilikitConstants::STATE_KNOWN_CLASSES);

    // Create node with UtiliKit classes.
    $node = Node::create([
      'type' => 'article',
      'title' => 'Test article',
      'body' => [
        'value' => '<div class="utilikit uk-pd--20 uk-mg--10">Test content</div>',
        'format' => 'full_html',
      ],
    ]);

    // Save the node.
    $node->save();

    // Verify classes were added.
    $knownClasses = $this->state->get(UtilikitConstants::STATE_KNOWN_CLASSES, []);
    $this->assertContains('uk-pd--20', $knownClasses);
    $this->assertContains('uk-mg--10', $knownClasses);

    // Verify CSS was generated.
    $generatedCss = $this->state->get(UtilikitConstants::STATE_GENERATED_CSS);
    $this->assertNotEmpty($generatedCss);
    $this->assertStringContainsString('.uk-pd--20', $generatedCss);
    $this->assertStringContainsString('.uk-mg--10', $generatedCss);
  }

  /**
   * Tests node save with auto-update disabled.
   */
  public function testNodeSaveWithoutAutoUpdate() {
    // Disable auto-update for nodes.
    $config = $this->configFactory->getEditable('utilikit.settings');
    $config->set('update_on_node_save', FALSE);
    $config->save();

    // Clear any existing classes.
    $this->state->delete(UtilikitConstants::STATE_KNOWN_CLASSES);

    // Create node with UtiliKit classes.
    $node = Node::create([
      'type' => 'article',
      'title' => 'Test article',
      'body' => [
        'value' => '<div class="utilikit uk-pd--30">Test content</div>',
        'format' => 'full_html',
      ],
    ]);

    // Save the node.
    $node->save();

    // Verify classes were NOT added.
    $knownClasses = $this->state->get(UtilikitConstants::STATE_KNOWN_CLASSES, []);
    $this->assertEmpty($knownClasses);
  }

  /**
   * Tests block content save with auto-update.
   */
  public function testBlockContentSave() {
    // Enable auto-update for blocks.
    $config = $this->configFactory->getEditable('utilikit.settings');
    $config->set('update_on_block_save', TRUE);
    $config->save();

    // Clear any existing classes.
    $this->state->delete(UtilikitConstants::STATE_KNOWN_CLASSES);

    // Create block with UtiliKit classes.
    $block = BlockContent::create([
      'type' => 'basic',
      'info' => 'Test block',
      'body' => [
        'value' => '<div class="utilikit uk-bg--ff0000 uk-tc--ffffff">Block content</div>',
        'format' => 'full_html',
      ],
    ]);

    // Save the block.
    $block->save();

    // Verify classes were added.
    $knownClasses = $this->state->get(UtilikitConstants::STATE_KNOWN_CLASSES, []);
    $this->assertContains('uk-bg--ff0000', $knownClasses);
    $this->assertContains('uk-tc--ffffff', $knownClasses);
  }

  /**
   * Tests paragraph save with auto-update.
   */
  public function testParagraphSave() {
    // Enable auto-update for paragraphs.
    $config = $this->configFactory->getEditable('utilikit.settings');
    $config->set('update_on_paragraph_save', TRUE);
    $config->save();

    // Clear any existing classes.
    $this->state->delete(UtilikitConstants::STATE_KNOWN_CLASSES);

    // Create paragraph with UtiliKit classes.
    $paragraph = Paragraph::create([
      'type' => 'text',
      'field_text' => [
        'value' => '<div class="utilikit uk-dp--flex uk-jc--center">Paragraph content</div>',
        'format' => 'full_html',
      ],
    ]);

    // Save the paragraph.
    $paragraph->save();

    // Verify classes were added.
    $knownClasses = $this->state->get(UtilikitConstants::STATE_KNOWN_CLASSES, []);
    $this->assertContains('uk-dp--flex', $knownClasses);
    $this->assertContains('uk-jc--center', $knownClasses);
  }

  /**
   * Tests entity save in inline mode.
   */
  public function testEntitySaveInlineMode() {
    // Switch to inline mode.
    $config = $this->configFactory->getEditable('utilikit.settings');
    $config->set('rendering_mode', 'inline');
    $config->set('update_on_node_save', TRUE);
    $config->save();

    // Clear any existing classes.
    $this->state->delete(UtilikitConstants::STATE_KNOWN_CLASSES);

    // Create node with UtiliKit classes.
    $node = Node::create([
      'type' => 'article',
      'title' => 'Test article',
      'body' => [
        'value' => '<div class="utilikit uk-pd--40">Test content</div>',
        'format' => 'full_html',
      ],
    ]);

    // Save the node.
    $node->save();

    // In inline mode, classes should still be tracked.
    $knownClasses = $this->state->get(UtilikitConstants::STATE_KNOWN_CLASSES, []);
    $this->assertContains('uk-pd--40', $knownClasses);
  }

  /**
   * Tests entity save with CSS update lock.
   */
  public function testEntitySaveWithLock() {
    // Enable auto-update.
    $config = $this->configFactory->getEditable('utilikit.settings');
    $config->set('update_on_node_save', TRUE);
    $config->save();

    // Acquire the lock to simulate another process updating CSS.
    $this->lock->acquire(UtilikitConstants::LOCK_CSS_UPDATE, 5);

    // Create node with UtiliKit classes.
    $node = Node::create([
      'type' => 'article',
      'title' => 'Test article',
      'body' => [
        'value' => '<div class="utilikit uk-pd--50">Test content</div>',
        'format' => 'full_html',
      ],
    ]);

    // Save the node.
    $node->save();

    // Verify item was queued.
    $queue = $this->queueFactory->get(UtilikitConstants::QUEUE_CSS_PROCESSOR);
    $this->assertGreaterThan(0, $queue->numberOfItems());

    // Get the queued item.
    $item = $queue->claimItem();
    $this->assertNotFalse($item);
    $this->assertEquals(['uk-pd--50'], $item->data['classes']);
    $this->assertEquals('node', $item->data['entity_type']);

    // Release lock.
    $this->lock->release(UtilikitConstants::LOCK_CSS_UPDATE);

    // Clean up.
    $queue->deleteItem($item);
  }

  /**
   * Tests multiple entities saving simultaneously.
   */
  public function testMultipleEntitySaves() {
    // Enable auto-update for all entity types.
    $config = $this->configFactory->getEditable('utilikit.settings');
    $config->set('update_on_node_save', TRUE);
    $config->set('update_on_block_save', TRUE);
    $config->save();

    // Clear any existing classes.
    $this->state->delete(UtilikitConstants::STATE_KNOWN_CLASSES);

    // Create and save multiple entities.
    $node = Node::create([
      'type' => 'article',
      'title' => 'Test article',
      'body' => [
        'value' => '<div class="utilikit uk-pd--60">Node content</div>',
        'format' => 'full_html',
      ],
    ]);
    $node->save();

    $block = BlockContent::create([
      'type' => 'basic',
      'info' => 'Test block',
      'body' => [
        'value' => '<div class="utilikit uk-mg--60">Block content</div>',
        'format' => 'full_html',
      ],
    ]);
    $block->save();

    // Verify all classes were added.
    $knownClasses = $this->state->get(UtilikitConstants::STATE_KNOWN_CLASSES, []);
    $this->assertContains('uk-pd--60', $knownClasses);
    $this->assertContains('uk-mg--60', $knownClasses);
  }

  /**
   * Tests entity save with invalid classes.
   */
  public function testEntitySaveInvalidClasses() {
    // Enable auto-update.
    $config = $this->configFactory->getEditable('utilikit.settings');
    $config->set('update_on_node_save', TRUE);
    $config->save();

    // Clear any existing classes.
    $this->state->delete(UtilikitConstants::STATE_KNOWN_CLASSES);

    // Create node with mixed valid and invalid classes.
    $node = Node::create([
      'type' => 'article',
      'title' => 'Test article',
      'body' => [
        'value' => '<div class="utilikit uk-pd--70 uk-invalid--class not-utility">Test content</div>',
        'format' => 'full_html',
      ],
    ]);

    // Save the node.
    $node->save();

    // Verify only valid classes were added.
    $knownClasses = $this->state->get(UtilikitConstants::STATE_KNOWN_CLASSES, []);
    $this->assertContains('uk-pd--70', $knownClasses);
    $this->assertNotContains('uk-invalid--class', $knownClasses);
    $this->assertNotContains('not-utility', $knownClasses);
  }

  /**
   * Tests entity save with no UtiliKit classes.
   */
  public function testEntitySaveNoClasses() {
    // Enable auto-update.
    $config = $this->configFactory->getEditable('utilikit.settings');
    $config->set('update_on_node_save', TRUE);
    $config->save();

    // Clear any existing classes.
    $this->state->delete(UtilikitConstants::STATE_KNOWN_CLASSES);

    // Create node without UtiliKit classes.
    $node = Node::create([
      'type' => 'article',
      'title' => 'Test article',
      'body' => [
        'value' => '<div class="regular-class">No utility classes here</div>',
        'format' => 'full_html',
      ],
    ]);

    // Save the node.
    $node->save();

    // Verify no classes were added.
    $knownClasses = $this->state->get(UtilikitConstants::STATE_KNOWN_CLASSES, []);
    $this->assertEmpty($knownClasses);
  }

  /**
   * Tests entity save with non-fieldable entity.
   */
  public function testNonFieldableEntitySave() {
    // Enable auto-update.
    $config = $this->configFactory->getEditable('utilikit.settings');
    $config->set('update_on_node_save', TRUE);
    $config->save();

    // Create a user (non-fieldable in our test setup)
    $user = $this->createUser();

    // This should not trigger any errors.
    $user->save();

    // Verify no errors occurred (test passes if no exceptions)
    $this->assertTrue(TRUE);
  }

  /**
   * Tests entity update vs create.
   */
  public function testEntityUpdate() {
    // Enable auto-update.
    $config = $this->configFactory->getEditable('utilikit.settings');
    $config->set('update_on_node_save', TRUE);
    $config->save();

    // Clear any existing classes.
    $this->state->delete(UtilikitConstants::STATE_KNOWN_CLASSES);

    // Create node with initial classes.
    $node = Node::create([
      'type' => 'article',
      'title' => 'Test article',
      'body' => [
        'value' => '<div class="utilikit uk-pd--80">Initial content</div>',
        'format' => 'full_html',
      ],
    ]);
    $node->save();

    // Verify initial classes.
    $knownClasses = $this->state->get(UtilikitConstants::STATE_KNOWN_CLASSES, []);
    $this->assertContains('uk-pd--80', $knownClasses);

    // Update node with new classes.
    $node->body->value = '<div class="utilikit uk-pd--80 uk-mg--80">Updated content</div>';
    $node->save();

    // Verify new classes were added.
    $knownClasses = $this->state->get(UtilikitConstants::STATE_KNOWN_CLASSES, []);
    $this->assertContains('uk-pd--80', $knownClasses);
    $this->assertContains('uk-mg--80', $knownClasses);
  }

  /**
   * Tests entity save with complex HTML structure.
   */
  public function testComplexHtmlStructure() {
    // Enable auto-update.
    $config = $this->configFactory->getEditable('utilikit.settings');
    $config->set('update_on_node_save', TRUE);
    $config->save();

    // Clear any existing classes.
    $this->state->delete(UtilikitConstants::STATE_KNOWN_CLASSES);

    // Create node with complex nested HTML.
    $html = '
      <div class="wrapper">
        <div class="utilikit uk-pd--20 uk-mg--10">
          <h2 class="utilikit uk-fs--24 uk-fw--700">Heading</h2>
          <div class="utilikit uk-dp--flex uk-jc--center">
            <span class="utilikit uk-tc--ff0000">Red text</span>
            <span class="utilikit uk-tc--00ff00">Green text</span>
          </div>
        </div>
      </div>
    ';

    $node = Node::create([
      'type' => 'article',
      'title' => 'Complex HTML',
      'body' => [
        'value' => $html,
        'format' => 'full_html',
      ],
    ]);
    $node->save();

    // Verify all unique classes were extracted.
    $knownClasses = $this->state->get(UtilikitConstants::STATE_KNOWN_CLASSES, []);
    $expectedClasses = [
      'uk-pd--20', 'uk-mg--10', 'uk-fs--24', 'uk-fw--700',
      'uk-dp--flex', 'uk-jc--center', 'uk-tc--ff0000', 'uk-tc--00ff00',
    ];

    foreach ($expectedClasses as $class) {
      $this->assertContains($class, $knownClasses);
    }
  }

  /**
   * Tests performance with large content.
   */
  public function testLargeContentPerformance() {
    // Enable auto-update.
    $config = $this->configFactory->getEditable('utilikit.settings');
    $config->set('update_on_node_save', TRUE);
    $config->save();

    // Generate large HTML with many classes.
    $html = '';
    for ($i = 0; $i < 100; $i++) {
      $html .= sprintf(
        '<div class="utilikit uk-pd--%d uk-mg--%d">Content %d</div>',
        $i % 50,
        $i % 30,
        $i
      );
    }

    $startTime = microtime(TRUE);

    $node = Node::create([
      'type' => 'article',
      'title' => 'Large content',
      'body' => [
        'value' => $html,
        'format' => 'full_html',
      ],
    ]);
    $node->save();

    $duration = microtime(TRUE) - $startTime;

    // Should complete in reasonable time.
    $this->assertLessThan(5.0, $duration, 'Large content should be processed within 5 seconds');

    // Verify classes were processed.
    $knownClasses = $this->state->get(UtilikitConstants::STATE_KNOWN_CLASSES, []);
    $this->assertNotEmpty($knownClasses);
  }

}

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

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