Last active
April 6, 2026 03:35
-
-
Save edutrul/38312bfac529cd054bf8dd083b1bfc57 to your computer and use it in GitHub Desktop.
How to deal with DTT with a specific paragraph like "Quote" and the correct parent classes following best practices.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| declare(strict_types=1); | |
| namespace Drupal\Tests\server_general\ExistingSite; | |
| use Drupal\Tests\drupal_test_assertions\Assertions\EntityTrait; | |
| use Drupal\Tests\drupal_test_assertions\Assertions\FieldsTrait; | |
| use weitzman\DrupalTestTraits\ExistingSiteBase; | |
| /** | |
| * Abstract base class for testing entity bundles. | |
| * | |
| * Automatically runs field existence and required/optional assertions | |
| * for every concrete test class via testFields(). | |
| */ | |
| abstract class EntityBundleTestBase extends ExistingSiteBase implements RequiredAndOptionalFieldTestInterface { | |
| use EntityTrait; | |
| use FieldsTrait; | |
| /** | |
| * Tests required and optional fields for this entity bundle. | |
| */ | |
| public function testFields(): void { | |
| $entity_type = $this->getEntityType(); | |
| $entity_bundle = $this->getEntityBundle(); | |
| $this->assertEntityExists($entity_type, $entity_bundle); | |
| foreach ($this->getRequiredFields() as $field_name) { | |
| $this->assertFieldIsRequired($field_name, $entity_type, $entity_bundle); | |
| } | |
| foreach ($this->getOptionalFields() as $field_name) { | |
| $this->assertFieldIsNotRequired($field_name, $entity_type, $entity_bundle); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| declare(strict_types=1); | |
| namespace Drupal\Tests\server_general\Traits; | |
| use Drupal\Core\File\FileExists; | |
| use Drupal\file\FileInterface; | |
| use weitzman\DrupalTestTraits\DrupalTrait; | |
| /** | |
| * Provides file entity creation for tests using committed test assets. | |
| * | |
| * Assets live in tests/assets/ and are copied to public:// with | |
| * FileExists::Replace, so files never accumulate across test runs. The | |
| * physical file persists in public:// intentionally — this is safe for | |
| * parallel tests and avoids teardown race conditions. | |
| * | |
| * Available assets: | |
| * - test-image.png | |
| * - test-image.jpg | |
| * - test-file.pdf | |
| */ | |
| trait FileCreationTrait { | |
| use DrupalTrait; | |
| const ASSETS_PATH = 'modules/custom/server_general/tests/assets/'; | |
| /** | |
| * Creates a File entity from a committed test asset. | |
| * | |
| * @param string $filename | |
| * The asset filename (e.g. 'test-image.png'). Must exist in tests/assets/. | |
| * | |
| * @return \Drupal\file\FileInterface | |
| * The saved File entity, marked for automatic cleanup. | |
| */ | |
| protected function createFileEntity(string $filename): FileInterface { | |
| $source = \Drupal::root() . '/' . self::ASSETS_PATH . $filename; | |
| $uri = \Drupal::service('file_system') | |
| ->copy($source, 'public://' . $filename, FileExists::Replace); | |
| /** @var \Drupal\file\FileInterface $file */ | |
| $file = \Drupal::entityTypeManager() | |
| ->getStorage('file') | |
| ->create([ | |
| 'uri' => $uri, | |
| 'status' => 1, | |
| ]); | |
| $file->setPermanent(); | |
| $file->save(); | |
| $this->markEntityForCleanup($file); | |
| return $file; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| declare(strict_types=1); | |
| namespace Drupal\Tests\server_general\Traits; | |
| use Drupal\paragraphs\Entity\Paragraph; | |
| use Drupal\paragraphs\ParagraphInterface; | |
| use weitzman\DrupalTestTraits\DrupalTrait; | |
| /** | |
| * Helps in creation of Paragraph entities in tests. | |
| */ | |
| trait ParagraphCreationTrait { | |
| use DrupalTrait; | |
| /** | |
| * Creates a Paragraph and marks it for automatic cleanup. | |
| * | |
| * @param array $settings | |
| * The settings to pass to Paragraph creation. | |
| * | |
| * @return \Drupal\paragraphs\ParagraphInterface | |
| * The created Paragraph entity. | |
| */ | |
| protected function createParagraph(array $settings = []): ParagraphInterface { | |
| /** @var \Drupal\paragraphs\ParagraphInterface $entity */ | |
| $entity = Paragraph::create($settings); | |
| $entity->save(); | |
| $this->markEntityForCleanup($entity); | |
| return $entity; | |
| } | |
| /** | |
| * Extract the reference values for a paragraph. | |
| * | |
| * @param \Drupal\paragraphs\ParagraphInterface $paragraph | |
| * The paragraph. | |
| * | |
| * @return array | |
| * Reference values containing target_id and target_revision_id. | |
| */ | |
| protected function getParagraphReferenceValues(ParagraphInterface $paragraph): array { | |
| return [ | |
| 'target_id' => $paragraph->id(), | |
| 'target_revision_id' => $paragraph->getRevisionId(), | |
| ]; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| declare(strict_types=1); | |
| namespace Drupal\Tests\server_general\ExistingSite; | |
| use Drupal\Tests\server_general\Traits\FileCreationTrait; | |
| use Drupal\Tests\server_general\Traits\ParagraphCreationTrait; | |
| use Symfony\Component\HttpFoundation\Response; | |
| use weitzman\DrupalTestTraits\Entity\MediaCreationTrait; | |
| /** | |
| * Test 'Quote' paragraph type. | |
| */ | |
| final class QuoteParagraphTest extends EntityBundleTestBase { | |
| use FileCreationTrait; | |
| use MediaCreationTrait; | |
| use ParagraphCreationTrait; | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getEntityType(): string { | |
| return 'paragraph'; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getEntityBundle(): string { | |
| return 'quote'; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getRequiredFields(): array { | |
| return [ | |
| 'field_body', | |
| 'field_image', | |
| ]; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getOptionalFields(): array { | |
| return [ | |
| 'field_subtitle', | |
| ]; | |
| } | |
| /** | |
| * Test render of the paragraph. | |
| */ | |
| public function testRender(): void { | |
| $file = $this->createFileEntity('test-image.png'); | |
| $media = $this->createMedia([ | |
| 'bundle' => 'image', | |
| 'name' => 'Test image', | |
| 'field_media_image' => [ | |
| 'target_id' => $file->id(), | |
| 'alt' => 'Test image alt', | |
| ], | |
| ]); | |
| $body = 'This is the body'; | |
| $subtitle = 'This is the subtitle'; | |
| $paragraph = $this->createParagraph([ | |
| 'type' => $this->getEntityBundle(), | |
| 'field_body' => $body, | |
| 'field_subtitle' => $subtitle, | |
| 'field_image' => [ | |
| 'target_id' => $media->id(), | |
| ], | |
| ]); | |
| $node = $this->createNode([ | |
| 'title' => 'Landing Page', | |
| 'type' => 'landing_page', | |
| 'field_paragraphs' => [ | |
| $this->getParagraphReferenceValues($paragraph), | |
| ], | |
| 'moderation_state' => 'published', | |
| ]); | |
| $node->setPublished()->save(); | |
| $this->drupalGet($node->toUrl()); | |
| $this->assertSession()->statusCodeEquals(Response::HTTP_OK); | |
| $this->assertSession()->elementTextContains('css', '.paragraph--type--quote', $body); | |
| $this->assertSession()->elementTextContains('css', '.paragraph--type--quote', $subtitle); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| declare(strict_types=1); | |
| namespace Drupal\Tests\server_general\ExistingSite; | |
| /** | |
| * Interface defining the contract for entity bundle field tests. | |
| */ | |
| interface RequiredAndOptionalFieldTestInterface { | |
| /** | |
| * Returns the entity type to test. | |
| * | |
| * @return string | |
| * An entity type name (e.g. 'node', 'paragraph'). | |
| */ | |
| public function getEntityType(): string; | |
| /** | |
| * Returns the entity bundle to test. | |
| * | |
| * @return string | |
| * A bundle name (e.g. 'quote', 'landing_page'). | |
| */ | |
| public function getEntityBundle(): string; | |
| /** | |
| * Returns the required fields for this entity bundle. | |
| * | |
| * @return string[] | |
| * Array of required field names. | |
| */ | |
| public function getRequiredFields(): array; | |
| /** | |
| * Returns the optional fields for this entity bundle. | |
| * | |
| * @return string[] | |
| * Array of optional field names. | |
| */ | |
| public function getOptionalFields(): array; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment