custom_field-1.0.x-dev/tests/src/FunctionalJavascript/FieldStorageSettingsTest.php

tests/src/FunctionalJavascript/FieldStorageSettingsTest.php
<?php

namespace Drupal\Tests\custom_field\FunctionalJavascript;

use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;

/**
 * Field storage settings form tests for custom field.
 *
 * @group custom_field
 */
class FieldStorageSettingsTest extends WebDriverTestBase {

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'custom_field_viewfield',
    'custom_field_test',
    'user',
    'system',
    'field',
    'field_ui',
    'text',
    'node',
    'path',
    'views',
  ];

  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'stark';

  /**
   * The custom fields on the test entity bundle.
   *
   * @var array|\Drupal\Core\Field\FieldDefinitionInterface[]
   */
  protected array $fields = [];

  /**
   * The field manager service.
   *
   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
   */
  protected $entityFieldManager;

  /**
   * The bundle type.
   *
   * @var string
   */
  protected $bundle;

  /**
   * The field name.
   *
   * @var string
   */
  protected string $fieldName;

  /**
   * The field array path.
   *
   * @var string
   */
  protected string $parentPath;

  /**
   * URL to field's storage configuration form.
   *
   * @var string
   */
  protected string $fieldStorageConfigUrl;

  /**
   * Entity form display.
   *
   * @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface
   */
  protected $formDisplay;

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

    $this->fieldName = 'field_test';
    $this->bundle = 'custom_field_entity_test';
    $this->fieldStorageConfigUrl = '/admin/structure/types/manage/' . $this->bundle . '/fields/node.' . $this->bundle . '.' . $this->fieldName;
    $this->entityFieldManager = $this->container->get('entity_field.manager');
    $this->fields = $this->entityFieldManager->getFieldDefinitions('node', $this->bundle);

    $this->drupalLogin($this->drupalCreateUser([], NULL, TRUE));
    $this->parentPath = 'field_storage[subform][settings][items]';
  }

  /**
   * Tests the settings form with stored configuration.
   */
  public function testFormSettings(): void {
    $field = $this->fields[$this->fieldName];
    $this->drupalGet($this->fieldStorageConfigUrl);
    $page = $this->getSession()->getPage();
    $assert_session = $this->assertSession();
    $columns = $field->getSetting('columns');

    // Verify the clone settings field exists.
    $assert_session->elementExists('css', '[name="field_storage[subform][settings][clone]"]');

    // Iterate over each column stored in config to test form element.
    foreach ($columns as $name => $column) {
      $has_unsigned = FALSE;
      $type = $column['type'];
      $length_field = $page->find('css', "input[name='$this->parentPath[$name][length]']");
      $size_field = $page->find('css', "select[name='$this->parentPath[$name][size]']");
      $precision_field = $page->find('css', "input[name='$this->parentPath[$name][precision]']");
      $scale_field = $page->find('css', "input[name='$this->parentPath[$name][scale]']");
      $unsigned_field = $page->find('css', "input[name='$this->parentPath[$name][unsigned]']");
      $datetime_type_field = $page->find('css', "select[name='$this->parentPath[$name][datetime_type]']");
      $target_type_field = $page->find('css', "select[name='$this->parentPath[$name][target_type]']");
      $uri_scheme_field = $page->find('css', "input[name='$this->parentPath[$name][uri_scheme]']");

      // Verify the type field is present and required.
      $type_field = $page->find('css', "select[name='$this->parentPath[$name][type]']");
      $this->assertNotNull($type_field, 'Type field exists');
      $this->assertTrue($type_field->hasAttribute('required'), 'Type field is required.');
      $this->assertEquals($type, $type_field->getValue(), 'The configured data type is selected');

      // Check 'length' field.
      if (in_array($type, ['string', 'telephone'])) {
        $this->assertNotNull($length_field, 'Length field exists');
        $this->assertEquals($column['length'], $length_field->getValue(), 'The configured value equals the form value.');
      }
      else {
        $this->assertNull($length_field, sprintf('Length field should not exist for type "%s"', $type));
      }

      // Check 'size' field.
      if (in_array($type, ['integer', 'float'])) {
        $has_unsigned = TRUE;
        $this->assertNotNull($size_field, 'Size field exists');
        $this->assertOptionSelected("$this->parentPath[$name][size]", $column['size'], 'The configured size is selected.');
      }
      else {
        $this->assertNull($size_field, sprintf('Size field should not exist for type "%s"', $type));
      }

      // Check decimal specific fields.
      if ($type === 'decimal') {
        $has_unsigned = TRUE;
        $this->assertNotNull($precision_field, 'Precision field exists');
        $this->assertNotNull($scale_field, 'Scale field exists');
      }
      else {
        $this->assertNull($precision_field, sprintf('Precision field should not exist for type "%s"', $type));
        $this->assertNull($scale_field, sprintf('Scale field should not exist for type "%s"', $type));
      }

      // Check 'unsigned' field.
      if ($has_unsigned) {
        $this->assertNotNull($unsigned_field, 'Unsigned field exists');
        $this->assertTrue($unsigned_field->isChecked() === (bool) $unsigned_field->getValue(), 'The unsigned field is checked if the value is true.');
      }
      else {
        $this->assertNull($unsigned_field, sprintf('Unsigned field should not exist for type "%s"', $type));
      }

      // Check 'datetime_type' field.
      if (in_array($type, ['datetime', 'daterange'])) {
        $this->assertNotNull($datetime_type_field, 'The datetime_type field exists.');
        $this->assertOptionSelected("$this->parentPath[$name][datetime_type]", $column['datetime_type'], 'The configured datetime type is selected.');
      }
      else {
        $this->assertNull($datetime_type_field, sprintf('The datetime_type field should not exist for type "%s"', $type));
      }

      // Check 'target_type' field.
      if ($type === 'entity_reference') {
        $this->assertNotNull($target_type_field, 'The target_type field exists.');
      }
      else {
        $this->assertNull($target_type_field, sprintf('The target_type field should not exist for type "%s"', $type));
      }

      // Check 'uri_scheme' field.
      if (in_array($type, ['file', 'image'])) {
        $this->assertNotNull($uri_scheme_field, 'The uri_scheme field exists');
      }
      else {
        $this->assertNull($uri_scheme_field, sprintf('The uri_scheme field should not exist for type "%s"', $type));
      }
    }
  }

  /**
   * Tests the add/remove columns buttons with stored configuration.
   */
  public function testAddRemoveColumns(): void {
    $this->drupalGet($this->fieldStorageConfigUrl);
    $field = $this->fields[$this->fieldName];
    $columns = $field->getSetting('columns');
    $page = $this->getSession()->getPage();
    // Remove elements in descending order until getting to the last one.
    $column_count = count($columns);
    foreach ($columns as $name => $column) {
      $button_id = "remove_$name";
      $this->assertSession()->waitForElementVisible('css', "[name='$button_id']", 5000);
      $remove_button = $page->find('css', "[name='$button_id']");
      if ($column_count === 1) {
        $this->assertNull($remove_button, 'Remove button exists');
      }
      else {
        $remove_button->click();
        $column_count--;
        // Wait for the AJAX request to complete and the element to disappear.
        $this->assertSession()->assertWaitOnAjaxRequest();
      }
      $this->assertSession()->elementNotExists('css', "[name='$button_id']");
    }

    // Count remaining columns.
    $settings_element = $page->find('css', '[data-drupal-selector="edit-field-storage-subform-settings-items"]');
    $this->assertNotNull($settings_element, 'Settings element not found.');
    $details_children = $settings_element->findAll('css', 'details');
    $count = count($details_children);
    $this->assertEquals(1, $count, 'Remaining column count matches expected.');

    // Click the Add another button and verify the new element exists.
    $add_button = $page->findButton('Add sub-field');
    $this->assertNotNull($add_button, 'Add sub-field button exists');
    $add_button->click();

    // Wait for the second <details> element to become visible.
    $this->assertSession()->waitForElementVisible('css', '#edit-field-storage-subform-settings-items details:nth-of-type(2)', 5000);
    $updated_details_children = $settings_element->findAll('css', 'details');
    $new_count = count($updated_details_children);
    $this->assertEquals(2, $new_count, 'New column count matches expected.');
  }

  /**
   * Tests cloning field settings from another field.
   */
  public function testCloneSettings(): void {
    $field_copy = $this->fields[$this->fieldName];
    $field_copy_columns = $field_copy->getFieldStorageDefinition()->getColumns();

    // Create a generic custom field for validation.
    $field_storage = FieldStorageConfig::create([
      'field_name' => 'field_custom_generic',
      'entity_type' => 'node',
      'type' => 'custom',
    ]);
    $field_storage->save();

    $field_instance = FieldConfig::create([
      'field_storage' => $field_storage,
      'bundle' => 'article',
      'label' => 'Generic custom field',
    ]);
    $field_instance->save();
    $article_config_url = '/admin/structure/types/manage/article/fields/node.article.field_custom_generic';

    // Set the article's form display.
    $this->formDisplay = EntityFormDisplay::load('node.article.default');

    if (!$this->formDisplay) {
      EntityFormDisplay::create([
        'targetEntityType' => 'node',
        'bundle' => 'article',
        'mode' => 'default',
        'status' => TRUE,
      ])->save();
      $this->formDisplay = EntityFormDisplay::load('node.article.default');
    }
    $this->formDisplay->setComponent('field_custom_generic', [
      'type' => 'custom_stacked',
    ])->save();

    $this->drupalGet($article_config_url);
    $page = $this->getSession()->getPage();
    $assert_session = $this->assertSession();

    // Verify the clone settings field exists.
    $assert_session->elementExists('css', '[name="field_storage[subform][settings][clone]"]');
    $clone_field = $page->findField('field_storage[subform][settings][clone]');
    $option_value = 'node.' . $this->bundle . '.' . $this->fieldName;
    $clone_field->setValue($option_value);
    $this->assertEquals($option_value, $clone_field->getValue(), 'Clone field is set to the correct value');
    $this->assertSession()->assertWaitOnAjaxRequest();
    $this->assertSession()->pageTextContainsOnce('The selected custom field field settings will be cloned. Any existing settings for this field will be overwritten. Field widget and formatter settings will not be cloned.');

    // Save the form.
    $save_button = $page->findButton('Save settings');
    $this->assertNotNull($save_button, 'Save settings button exists');
    $save_button->press();
    $this->assertSession()->assert($this->assertSession()->waitForText("Saved Generic custom field configuration."), 'text not found');

    // Load the cloned storage and see if they match the source.
    $field_storage = FieldStorageConfig::loadByName('node', 'field_custom_generic');
    $columns = $field_storage->getColumns();
    $this->assertEquals($field_copy_columns, $columns, 'The cloned columns match the source columns.');
    $this->drupalGet($article_config_url);
  }

  /**
   * Asserts that a select field has a selected option.
   *
   * @param string $id
   *   ID of select field to assert.
   * @param string $option
   *   Option to assert.
   * @param string $message
   *   (optional) A message to display with the assertion. Do not translate
   *   messages: use \Drupal\Component\Utility\SafeMarkup::format() to embed
   *   variables in the message text, not t(). If left blank, a default message
   *   will be displayed.
   */
  protected function assertOptionSelected(string $id, string $option, string $message = ''): void {
    $select = $this->getSession()->getPage()->findField($id);
    $this->assertNotNull($select, "Select field $id exists");
    $this->assertEquals($option, $select->getValue(), $message ?: "Option $option for field $id is selected.");
  }

}

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

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