eav_field-2.x-dev/tests/src/Functional/EavFieldTest.php

tests/src/Functional/EavFieldTest.php
<?php

namespace Drupal\Tests\eav_field\Functional;

use Drupal\commerce_product\Entity\Product;
use Drupal\commerce_store\Entity\Store;
use Drupal\Core\Field\FieldItemList;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Url;
use Drupal\eav_field\Entity\EavAttribute;
use Drupal\eav_field\Entity\EavAttributeInterface;
use Drupal\eav_field\Entity\EavValue;
use Drupal\eav_field\Entity\EavValueInterface;
use Drupal\eav_field\Plugin\Field\FieldType\EavItemInterface;
use Drupal\eav_field\Plugin\Field\FieldType\EavItemListInterface;
use Drupal\entity\BundleFieldDefinition;
use Drupal\field\Entity\FieldConfig;
use Drupal\node\Entity\Node;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\taxonomy\TermInterface;
use Drupal\taxonomy\VocabularyInterface;
use Drupal\Tests\block\Traits\BlockCreationTrait;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\eav_field\Traits\EavFieldTestTrait;
use Drupal\Tests\improvements\Traits\ImprovementsTestTrait;
use Drupal\Tests\node\Traits\NodeCreationTrait;
use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
use Drupal\Tests\WebAssert;

class EavFieldTest extends BrowserTestBase {

  use BlockCreationTrait;
  use EavFieldTestTrait;
  use ImprovementsTestTrait;
  use NodeCreationTrait;
  use TaxonomyTestTrait;

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

  /**
   * {@inheritDoc}
   */
  protected static $modules = [
    'block',
    'eav_field',
    'field_ui',
    'node',
    'taxonomy',
    'user',
  ];

  protected VocabularyInterface $vocabulary;

  /**
   * @var TermInterface[]
   */
  protected array $categories = [];

  protected WebAssert $web_assert;

  protected function setUp(): void {
    parent::setUp();

    $this->drupalLoginAsRoot();

    // Create node types
    $this->createContentType(['type' => 'product', 'name' => 'Product node']);
    $this->createContentType(['type' => 'page', 'name' => 'Page node']);

    // Create "category" vocabulary
    $this->vocabulary = Vocabulary::create(['name' => 'Categories', 'vid' => 'category']);
    $this->vocabulary->save();

    // Create categories
    $categories_map = [
      'all'                          => 'All',
      'string_attr'                  => 'String',
      'second_string_attr'           => 'Second string',
      'string_long_attr'             => 'Long string',
      'integer_attr'                 => 'Integer',
      'decimal_attr'                 => 'Decimal',
      'boolean_attr'                 => 'Boolean',
      'entity_reference_attr'        => 'Entity reference',
      'list_string_attr'             => 'List string',
      'list_integer_attr'            => 'List integer',
      'simple_attr'                  => 'Simple',
      'multi_string_attr'            => 'Multi string',
      'string_and_multi_string_attr' => 'String + Multi string',
    ];
    foreach ($categories_map as $attribute_machine_name => $category_name) {
      $this->categories[$attribute_machine_name] = $this->createTerm($this->vocabulary, ['name' => $category_name]);
    }

    // Create "field_category" node field
    $this->createField(
      'node',
      'product',
      'field_category',
      'entity_reference',
      'Category',
      [
        'settings' => [
          'target_type' => 'taxonomy_term'
        ]
      ],
      [
        'settings' => [
          'handler' => 'default:taxonomy_term',
          'handler_settings' => [
            'target_bundles' => [
              'category' => 'category',
            ],
          ],
        ]
      ],
      'options_select',
      [],
      'entity_reference_label',
      [],
    );

    // Module initial setup
    $eav_attribute_category_field = FieldConfig::load('eav_attribute.eav_attribute.category');
    $eav_attribute_category_field_settings = $eav_attribute_category_field->get('settings');
    $eav_attribute_category_field_settings['handler_settings']['target_bundles']['category'] = 'category';
    $eav_attribute_category_field->set('settings', $eav_attribute_category_field_settings);
    $eav_attribute_category_field->save();

    // Create field "field_eav"
    $this->createEavField('node', 'product', 'field_eav', 'EAV attributes');

    // Place blocks
    $this->placeBlock('page_title_block', [
      'id' => 'page_title_block',
      'region' => 'content',
      'weight' => -100,
    ]);
    $this->placeBlock('local_tasks_block', [
      'id' => 'local_tasks_block',
      'region' => 'content',
      'weight' => -99,
    ]);
    $this->placeBlock('local_actions_block', [
      'id' => 'local_actions_block',
      'region' => 'content',
      'weight' => -98,
    ]);

    $this->web_assert = $this->assertSession();
  }

  public function testMain(): void {
    // Run all test with "_test" prefix
    $class_methods = get_class_methods(self::class);
    foreach ($class_methods as $class_method) {
      if (str_starts_with($class_method, '_test')) {
        $result = $this->{$class_method}();
        if ($result === FALSE) {
          break;
        }
      }
    }
  }

  private function _testInitialSetup(): void {
    $this->drupalGet('admin/structure/eav/attributes/fields/eav_attribute.eav_attribute.category');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldExists('settings[handler_settings][target_bundles][category]');
    $this->web_assert->checkboxChecked('settings[handler_settings][target_bundles][category]');

    $this->drupalGet('admin/structure/types/manage/product/fields');
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', '#field-eav');
    $this->web_assert->elementExists('css', '#field-category');

    $this->drupalGet('admin/structure/types/manage/product/form-display');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('fields[field_eav][type]', 'eav_widget');
    $this->web_assert->fieldValueEquals('fields[field_category][type]', 'options_select');

    $this->drupalGet('admin/structure/types/manage/product/display');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('fields[field_eav][type]', 'eav_formatter');
    $this->web_assert->fieldValueEquals('fields[field_category][type]', 'entity_reference_label');
  }

  private function _testAddEavFieldFromUi(): void {
    $field = [
      'label' => 'Test EAV attributes field',
      'name' => 'test_eav_attributes',
    ];

    $this->drupalGet('admin/structure/types/manage/product/fields/add-field');
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'input[name="new_storage_type"][value="eav"]');

    $this->submitForm([
      'new_storage_type' => 'eav',
    ], 'Continue');
    $this->dontSeeErrorMessage();
    $this->web_assert->elementContains('css', 'h1', 'Add field');

    $this->submitForm([
      'label' => $field['label'],
      'field_name' => $field['name'],
    ], 'Continue');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('label', 'Test EAV attributes field');

    $this->submitForm([
      'label' => $field['label'],
    ], 'Save settings');
    $this->dontSeeErrorMessage();
    $this->web_assert->pageTextContains('Saved ' . $field['label'] . ' configuration.');
    $this->web_assert->pageTextContains($field['name']);

    $this->drupalGet('admin/structure/types/manage/product/form-display');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('fields[field_eav][type]', 'eav_widget');

    $this->drupalGet('admin/structure/types/manage/product/display');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('fields[field_eav][type]', 'eav_formatter');

    // Delete field
    $this->drupalGet('admin/structure/types/manage/product/fields/node.product.field_' . $field['name'] . '/delete');
    $this->dontSeeErrorMessage();
    $this->submitForm([], 'Delete');
    $this->dontSeeErrorMessage();
    $this->web_assert->pageTextMatches('/The field .+ has been deleted from the .+ content type/');
    $this->web_assert->pageTextNotContains($field['name']);
  }

  private function _testAttributesPage(): void {
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementContains('css', 'h1', 'Attributes');
    $this->web_assert->elementExists('css', '#block-local-tasks-block a[href="/admin/structure/eav/attributes/fields"]');
    $this->web_assert->elementExists('css', '#block-local-tasks-block a[href="/admin/structure/eav/attributes/form-display"]');
    $this->web_assert->elementExists('css', '#block-local-tasks-block a[href="/admin/structure/eav/attributes/display"]');
    $this->web_assert->elementExists('css', 'form#eav-attribute-list');
  }


  private function _testAddAttributeFromUi_FirstStep(): void {
    $attribute = [
      'label' => 'String attribute (test first step)',
      'machine_name' => 'string_attr_first',
      'value_type' => 'string',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [
          'max_length' => 200,
        ],
      ],
      'value_config' => [
        'description' => 'String attribute value field description',
        'required' => FALSE,
        'default_value' => [
          0 => [
            'value' => 'String attribute default value',
          ],
        ],
        'settings' => [],
      ],
      'value_widget_type' => 'string_textfield',
      'value_widget_settings' => [
        'size' => 50,
        'placeholder' => 'String attribute placeholder',
      ],
      'value_formatter_type' => 'string',
      'value_formatter_settings' => [
        'link_to_entity' => FALSE,
      ],
      'description' => '',
      'category' => [
        $this->categories['string_attr']->id(),
        $this->categories['string_and_multi_string_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];

    // Check attribute form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->clickLink('Add attribute');
    $this->dontSeeErrorMessage();
    $this->web_assert->elementContains('css', 'h1', 'Adding attribute');
    $this->web_assert->fieldExists('label[0][value]');
    $this->web_assert->fieldExists('admin_label[0][value]');
    $this->web_assert->fieldExists('machine_name[0][value]');
    $this->web_assert->fieldExists('value_type');
    $this->web_assert->fieldExists('value_widget_type');
    $this->web_assert->fieldExists('value_formatter_type');
    $this->web_assert->fieldExists('category[' . $attribute['category'][0] . ']');
    $this->web_assert->fieldExists('category[' . $attribute['category'][1] . ']');
    $this->web_assert->fieldExists('category[' . $attribute['category'][2] . ']');
    $this->web_assert->fieldExists('description[0][value]');
    $this->web_assert->fieldExists('primary[value]');
    $this->web_assert->fieldExists('weight[0][value]');

    // Create attribute from ui
    $this->submitForm([
      'label[0][value]' => $attribute['label'],
      'machine_name[0][value]' => $attribute['machine_name'],
      'value_type' => $attribute['value_type'],
      'value_widget_type' => $attribute['value_widget_type'],
      'value_formatter_type' => $attribute['value_formatter_type'],
      'category[' . $attribute['category'][0] . ']' => TRUE,
      'category[' . $attribute['category'][1] . ']' => TRUE,
      'category[' . $attribute['category'][2] . ']' => TRUE,
      'description[0][value]' => $attribute['value_config']['default_value'][0]['value'],
    ], 'Save');
    $this->dontSeeErrorMessage();
    $attribute_id = $this->getLastAddedEavAttributeId();

    // Check attribute form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.edit_form', ['eav_attribute' => $attribute_id]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('label[0][value]', $attribute['label']);
    $this->web_assert->fieldValueEquals('machine_name[0][value]', $attribute['machine_name']);
    $this->web_assert->fieldValueEquals('value_type', $attribute['value_type']);
    $this->web_assert->fieldValueEquals('value_widget_type', $attribute['value_widget_type']);
    $this->web_assert->fieldValueEquals('value_formatter_type', $attribute['value_formatter_type']);
    $this->web_assert->checkboxChecked('category[' . $attribute['category'][0] . ']');
    $this->web_assert->checkboxChecked('category[' . $attribute['category'][1] . ']');
    $this->web_assert->checkboxChecked('category[' . $attribute['category'][2] . ']');
    $this->web_assert->checkboxNotChecked('category[' . $this->categories['integer_attr']->id() . ']');

    EavAttribute::load($attribute_id)->delete();
  }

  private function _testAddAttributeFromUi_StorageSettingsStep(): void {
    $attribute = [
      'label' => 'String attribute (test storage settings)',
      'machine_name' => 'string_attr_storage',
      'value_type' => 'string',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [
          'max_length' => 200,
        ],
      ],
      'value_config' => [
        'description' => 'String attribute value field description',
        'required' => FALSE,
        'default_value' => [
          0 => [
            'value' => 'String attribute default value',
          ],
        ],
        'settings' => [],
      ],
      'value_widget_type' => 'string_textfield',
      'value_widget_settings' => [
        'size' => 50,
        'placeholder' => 'String attribute placeholder',
      ],
      'value_formatter_type' => 'string',
      'value_formatter_settings' => [
        'link_to_entity' => FALSE,
      ],
      'description' => '',
      'category' => [
        $this->categories['string_attr']->id(),
        $this->categories['string_and_multi_string_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];

    // Create attribute from ui
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.add_form'));
    $this->submitForm([
      'label[0][value]' => $attribute['label'],
      'machine_name[0][value]' => $attribute['machine_name'],
      'value_type' => $attribute['value_type'],
      'value_widget_type' => $attribute['value_widget_type'],
      'value_formatter_type' => $attribute['value_formatter_type'],
      'category[' . $attribute['category'][0] . ']' => TRUE,
      'category[' . $attribute['category'][1] . ']' => TRUE,
      'category[' . $attribute['category'][2] . ']' => TRUE,
      'description[0][value]' => $attribute['value_config']['default_value'][0]['value'],
    ], 'Save');
    $this->dontSeeErrorMessage();
    $attribute_id = $this->getLastAddedEavAttributeId();
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_storage_form', ['eav_attribute' => $attribute_id]));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementContains('css', 'h1', 'Storage settings of attribute "' . $attribute['label'] . '"');
    $this->web_assert->fieldExists('settings[max_length]');
    $this->web_assert->fieldEnabled('settings[max_length]');
    $this->web_assert->fieldExists('cardinality');
    $this->web_assert->fieldExists('cardinality_number');

    // Save storage settings
    $this->submitForm([
      'settings[max_length]' => $attribute['value_storage_config']['settings']['max_length'],
    ], 'Continue');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('settings[max_length]', $attribute['value_storage_config']['settings']['max_length']);
    $this->web_assert->fieldEnabled('settings[max_length]');
    $this->web_assert->fieldValueEquals('cardinality', 'number');
    $this->web_assert->fieldValueEquals('cardinality_number', $attribute['value_storage_config']['cardinality']);

    EavAttribute::load($attribute_id)->delete();
  }

  private function _testAddAttributeFromUi_FieldSettingsStep(): void {
    $attribute = [
      'label' => 'String attribute (test field settings)',
      'machine_name' => 'string_attr_field',
      'value_type' => 'string',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [
          'max_length' => 200,
        ],
      ],
      'value_config' => [
        'description' => 'String attribute value field description',
        'required' => FALSE,
        'default_value' => [
          0 => [
            'value' => 'String attribute default value',
          ],
        ],
        'settings' => [],
      ],
      'value_widget_type' => 'string_textfield',
      'value_widget_settings' => [
        'size' => 50,
        'placeholder' => 'String attribute placeholder',
      ],
      'value_formatter_type' => 'string',
      'value_formatter_settings' => [
        'link_to_entity' => FALSE,
      ],
      'description' => '',
      'category' => [
        $this->categories['string_attr']->id(),
        $this->categories['string_and_multi_string_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];

    // Create attribute from ui
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.add_form'));
    $this->submitForm([
      'label[0][value]' => $attribute['label'],
      'machine_name[0][value]' => $attribute['machine_name'],
      'value_type' => $attribute['value_type'],
      'value_widget_type' => $attribute['value_widget_type'],
      'value_formatter_type' => $attribute['value_formatter_type'],
      'category[' . $attribute['category'][0] . ']' => TRUE,
      'category[' . $attribute['category'][1] . ']' => TRUE,
      'category[' . $attribute['category'][2] . ']' => TRUE,
      'description[0][value]' => $attribute['value_config']['default_value'][0]['value'],
    ], 'Save');
    $this->dontSeeErrorMessage();
    $attribute_id = $this->getLastAddedEavAttributeId();

    // Save storage settings
    $this->submitForm([
      'settings[max_length]' => $attribute['value_storage_config']['settings']['max_length'],
    ], 'Continue');

    // Check field settings form
    $this->dontSeeErrorMessage();
    $this->web_assert->elementContains('css', 'h1', 'Field settings of attribute "' . $attribute['label'] . '"');
    $this->web_assert->fieldExists('description');
    $this->web_assert->fieldExists('required');
    $this->web_assert->fieldExists('default_value_input[string_value][0][value]');

    // Save field settings
    $this->submitForm([
      'description' => $attribute['value_config']['description'],
      'set_default_value' => (int)(!empty($attribute['value_config']['default_value'])),
    ], 'Save settings');
    $this->dontSeeErrorMessage();
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_field_form', ['eav_attribute' => $attribute_id]));
    $this->web_assert->fieldValueEquals('description', $attribute['value_config']['description']);

    EavAttribute::load($attribute_id)->delete();
  }

  private function _testAddAttributeFromUi_FieldSettingsStepDefaultValue(): void {
    $attribute = [
      'label' => 'String attribute (test default value)',
      'machine_name' => 'string_attr_default_value',
      'value_type' => 'string',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [
          'max_length' => 200,
        ],
      ],
      'value_config' => [
        'description' => 'String attribute value field description',
        'required' => FALSE,
        'default_value' => [
          0 => [
            'value' => 'String attribute default value',
          ],
        ],
        'settings' => [],
      ],
      'value_widget_type' => 'string_textfield',
      'value_widget_settings' => [
        'size' => 50,
        'placeholder' => 'String attribute placeholder',
      ],
      'value_formatter_type' => 'string',
      'value_formatter_settings' => [
        'link_to_entity' => FALSE,
      ],
      'description' => '',
      'category' => [
        $this->categories['string_attr']->id(),
        $this->categories['string_and_multi_string_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];

    // Create attribute from ui
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.add_form'));
    $this->submitForm([
      'label[0][value]' => $attribute['label'],
      'machine_name[0][value]' => $attribute['machine_name'],
      'value_type' => $attribute['value_type'],
      'value_widget_type' => $attribute['value_widget_type'],
      'value_formatter_type' => $attribute['value_formatter_type'],
      'category[' . $attribute['category'][0] . ']' => TRUE,
      'category[' . $attribute['category'][1] . ']' => TRUE,
      'category[' . $attribute['category'][2] . ']' => TRUE,
      'description[0][value]' => $attribute['value_config']['default_value'][0]['value'],
    ], 'Save');
    $attribute_id = $this->getLastAddedEavAttributeId();

    // Save storage settings
    $this->submitForm([
      'settings[max_length]' => $attribute['value_storage_config']['settings']['max_length'],
    ], 'Continue');

    // Save field settings form
    $this->submitForm([
      'set_default_value' => 1,
      'default_value_input[string_value][0][value]' => $attribute['value_config']['default_value'][0]['value'],
    ], 'Save settings');

    // Check field settings form
    $this->dontSeeErrorMessage();
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_field_form', ['eav_attribute' => $attribute_id]));
    $this->web_assert->fieldValueEquals('default_value_input[string_value][0][value]', $attribute['value_config']['default_value'][0]['value']);

    EavAttribute::load($attribute_id)->delete();
  }

  private function _testAddAttributeFromUi_WidgetSettingsStep(): void {
    $attribute = [
      'label' => 'String attribute (test widget setting)',
      'machine_name' => 'string_attr_widget',
      'value_type' => 'string',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [
          'max_length' => 200,
        ],
      ],
      'value_config' => [
        'description' => 'String attribute value field description',
        'required' => FALSE,
        'default_value' => [
          0 => [
            'value' => 'String attribute default value',
          ],
        ],
        'settings' => [],
      ],
      'value_widget_type' => 'string_textfield',
      'value_widget_settings' => [
        'size' => 50,
        'placeholder' => 'String attribute placeholder',
      ],
      'value_formatter_type' => 'string',
      'value_formatter_settings' => [
        'link_to_entity' => FALSE,
      ],
      'description' => '',
      'category' => [
        $this->categories['string_attr']->id(),
        $this->categories['string_and_multi_string_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];

    // Create attribute from ui
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.add_form'));
    $this->submitForm([
      'label[0][value]' => $attribute['label'],
      'machine_name[0][value]' => $attribute['machine_name'],
      'value_type' => $attribute['value_type'],
      'value_widget_type' => $attribute['value_widget_type'],
      'value_formatter_type' => $attribute['value_formatter_type'],
      'category[' . $attribute['category'][0] . ']' => TRUE,
      'category[' . $attribute['category'][1] . ']' => TRUE,
      'category[' . $attribute['category'][2] . ']' => TRUE,
      'description[0][value]' => $attribute['value_config']['default_value'][0]['value'],
    ], 'Save');
    $attribute_id = $this->getLastAddedEavAttributeId();

    // Save storage settings
    $this->submitForm([
      'settings[max_length]' => $attribute['value_storage_config']['settings']['max_length'],
    ], 'Continue');

    // Save field settings
    $this->submitForm([
      'description' => $attribute['value_config']['description'],
      'set_default_value' => (int)(!empty($attribute['value_config']['default_value'])),
      'default_value_input[string_value][0][value]' => $attribute['value_config']['default_value'][0]['value'],
    ], 'Save settings');

    // Check widget settings form
    $this->web_assert->elementContains('css', 'h1', 'Widget settings of attribute "' . $attribute['label'] . '"');
    $this->web_assert->fieldExists('fields[string_value][settings_edit_form][settings][size]');
    $this->web_assert->fieldExists('fields[string_value][settings_edit_form][settings][placeholder]');

    // Save widget settings
    $this->submitForm([
      'fields[string_value][settings_edit_form][settings][size]' => $attribute['value_widget_settings']['size'],
      'fields[string_value][settings_edit_form][settings][placeholder]' => $attribute['value_widget_settings']['placeholder'],
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_widget_form', ['eav_attribute' => $attribute_id]));
    $this->web_assert->fieldValueEquals('fields[string_value][settings_edit_form][settings][size]', $attribute['value_widget_settings']['size']);
    $this->web_assert->fieldValueEquals('fields[string_value][settings_edit_form][settings][placeholder]', $attribute['value_widget_settings']['placeholder']);

    EavAttribute::load($attribute_id)->delete();
  }

  private function _testAddAttributeFromUi_FormatterSettingsStep(): void {
    $attribute = [
      'label' => 'String attribute (test formatter settings)',
      'machine_name' => 'string_attr_formatter',
      'value_type' => 'string',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [
          'max_length' => 200,
        ],
      ],
      'value_config' => [
        'description' => 'String attribute value field description',
        'required' => FALSE,
        'default_value' => [
          0 => [
            'value' => 'String attribute default value',
          ],
        ],
        'settings' => [],
      ],
      'value_widget_type' => 'string_textfield',
      'value_widget_settings' => [
        'size' => 50,
        'placeholder' => 'String attribute placeholder',
      ],
      'value_formatter_type' => 'string',
      'value_formatter_settings' => [
        'link_to_entity' => FALSE,
      ],
      'description' => '',
      'category' => [
        $this->categories['string_attr']->id(),
        $this->categories['string_and_multi_string_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];

    // Create attribute from ui
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.add_form'));
    $this->submitForm([
      'label[0][value]' => $attribute['label'],
      'machine_name[0][value]' => $attribute['machine_name'],
      'value_type' => $attribute['value_type'],
      'value_widget_type' => $attribute['value_widget_type'],
      'value_formatter_type' => $attribute['value_formatter_type'],
      'category[' . $attribute['category'][0] . ']' => TRUE,
      'category[' . $attribute['category'][1] . ']' => TRUE,
      'category[' . $attribute['category'][2] . ']' => TRUE,
      'description[0][value]' => $attribute['value_config']['default_value'][0]['value'],
    ], 'Save');
    $attribute_id = $this->getLastAddedEavAttributeId();

    // Save storage settings
    $this->submitForm([
      'settings[max_length]' => $attribute['value_storage_config']['settings']['max_length'],
    ], 'Continue');

    // Save field settings
    $this->submitForm([
      'description' => $attribute['value_config']['description'],
      'set_default_value' => (int)(!empty($attribute['value_config']['default_value'])),
      'default_value_input[string_value][0][value]' => $attribute['value_config']['default_value'][0]['value'],
    ], 'Save settings');

    // Save widget settings
    $this->submitForm([
      'fields[string_value][settings_edit_form][settings][size]' => $attribute['value_widget_settings']['size'],
      'fields[string_value][settings_edit_form][settings][placeholder]' => $attribute['value_widget_settings']['placeholder'],
    ], 'Save');

    // Check formatter settings form
    $this->web_assert->elementContains('css', 'h1', 'Formatter settings of attribute "' . $attribute['label'] . '"');
    $this->web_assert->pageTextContains('No settings.');
    $this->submitForm([], 'Save');
    $this->dontSeeErrorMessage();

    EavAttribute::load($attribute_id)->delete();
  }


  private function _testAddAttributeFromCode_String(): void {
    $attribute_values = [
      'label' => 'String attribute',
      'machine_name' => 'string_attr',
      'value_type' => 'string',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [
          'max_length' => 210,
        ],
      ],
      'value_config' => [
        'description' => 'String attribute value field description',
        'required' => FALSE,
        'default_value' => [
          0 => [
            'value' => 'String attribute default value',
          ],
        ],
        'settings' => [],
      ],
      'value_widget_type' => 'string_textfield',
      'value_widget_settings' => [
        'size' => 40,
        'placeholder' => '',
      ],
      'value_formatter_type' => 'string',
      'value_formatter_settings' => [
        'link_to_entity' => FALSE,
      ],
      'description' => '',
      'category' => [
        $this->categories['string_attr']->id(),
        $this->categories['string_and_multi_string_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];
    $attribute = EavAttribute::create($attribute_values);
    $attribute->save();

    // Check if attribute has been created
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'tr[data-drupal-selector="edit-eav-attributes-' . $attribute->id() . '"]');

    // Check Attribute edit form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.edit_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('label[0][value]', $attribute_values['label']);
    $this->web_assert->fieldValueEquals('machine_name[0][value]', $attribute_values['machine_name']);
    $this->web_assert->fieldValueEquals('value_type', $attribute_values['value_type']);
    $this->web_assert->fieldValueEquals('value_widget_type', $attribute_values['value_widget_type']);
    $this->web_assert->fieldValueEquals('value_formatter_type', $attribute_values['value_formatter_type']);
    $this->web_assert->checkboxChecked('category[' . $attribute_values['category'][0] . ']');
    $this->web_assert->checkboxChecked('category[' . $attribute_values['category'][1] . ']');
    $this->web_assert->fieldValueEquals('description[0][value]', $attribute_values['description']);

    // Check Storage settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_storage_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('settings[max_length]', $attribute_values['value_storage_config']['settings']['max_length']);
    $this->web_assert->fieldValueEquals('cardinality', 'number');
    $this->web_assert->fieldValueEquals('cardinality_number', $attribute_values['value_storage_config']['cardinality']);

    // Check Field settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_field_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('description', $attribute_values['value_config']['description']);
    $this->web_assert->fieldValueEquals('default_value_input[string_value][0][value]', $attribute_values['value_config']['default_value'][0]['value']);

    // Check Widget settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_widget_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('fields[string_value][settings_edit_form][settings][size]', $attribute_values['value_widget_settings']['size']);
    $this->web_assert->fieldValueEquals('fields[string_value][settings_edit_form][settings][placeholder]', $attribute_values['value_widget_settings']['placeholder']);

    // Check formatter settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_formatter_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->pageTextContains('No settings');
  }

  private function _testAddAttributeFromCode_SecondString(): void {
    $attribute_values = [
      'label' => 'Second string attribute',
      'machine_name' => 'second_string_attr',
      'value_type' => 'string',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [
          'max_length' => 255,
        ],
      ],
      'value_config' => [
        'description' => '',
        'required' => FALSE,
        'default_value' => [],
        'settings' => [],
      ],
      'value_widget_type' => 'string_textfield',
      'value_widget_settings' => [
        'size' => 60,
        'placeholder' => '',
      ],
      'value_formatter_type' => 'string',
      'value_formatter_settings' => [
        'link_to_entity' => FALSE,
      ],
      'description' => '',
      'category' => [
        $this->categories['second_string_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];
    $attribute = EavAttribute::create($attribute_values);
    $attribute->save();

    // Check if attribute has been created
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'tr[data-drupal-selector="edit-eav-attributes-' . $attribute->id() . '"]');
  }

  private function _testAddAttributeFromCode_StringLong(): void {
    $attribute_values = [
      'label' => 'Long string attribute',
      'machine_name' => 'string_long_attr',
      'value_type' => 'string_long',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [
          'case_sensitive' => FALSE,
        ],
      ],
      'value_config' => [
        'description' => 'Value field description',
        'required' => FALSE,
        'default_value' => [],
        'settings' => [],
      ],
      'value_widget_type' => 'string_textarea',
      'value_widget_settings' => [
        'rows' => 6,
        'placeholder' => 'Long string attribute value placeholder',
      ],
      'value_formatter_type' => 'basic_string',
      'value_formatter_settings' => [],
      'description' => 'Attribute description',
      'category' => [
        $this->categories['string_long_attr'],
        $this->categories['all'],
      ],
    ];
    $attribute = EavAttribute::create($attribute_values);
    $attribute->save();

    // Check if attribute has been created
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'tr[data-drupal-selector="edit-eav-attributes-' . $attribute->id() . '"]');

    // Attribute edit form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.edit_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('value_type', $attribute_values['value_type']);
    $this->web_assert->fieldValueEquals('value_widget_type', $attribute_values['value_widget_type']);
    $this->web_assert->fieldValueEquals('value_formatter_type', $attribute_values['value_formatter_type']);

    // Storage settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_storage_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('cardinality', 'number');
    $this->web_assert->fieldValueEquals('cardinality_number', $attribute_values['value_storage_config']['cardinality']);

    // Field settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_field_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('description', $attribute_values['value_config']['description']);
    $this->web_assert->fieldValueEquals('default_value_input[string_long_value][0][value]', '');

    // Widget settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_widget_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('fields[string_long_value][settings_edit_form][settings][rows]', $attribute_values['value_widget_settings']['rows']);
    $this->web_assert->fieldValueEquals('fields[string_long_value][settings_edit_form][settings][placeholder]', $attribute_values['value_widget_settings']['placeholder']);

    // Formatter form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_formatter_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->pageTextContains('No settings.');
  }

  private function _testAddAttributeFromCode_Integer(): void {
    $attribute_values = [
      'label' => 'Integer attribute',
      'machine_name' => 'integer_attr',
      'value_type' => 'integer',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [
          'unsigned' => FALSE,
          'size' => 'normal',
        ],
      ],
      'value_config' => [
        'description' => '',
        'required' => FALSE,
        'default_value' => [],
        'settings' => [
          'min' => '0',
          'max' => '1000',
          'prefix' => '',
          'suffix' => 'sffx',
        ],
      ],
      'value_widget_type' => 'number',
      'value_widget_settings' => [
        'placeholder' => '',
      ],
      'value_formatter_type' => 'number_integer',
      'value_formatter_settings' => [
        'thousand_separator' => ' ',
        'prefix_suffix' => TRUE,
      ],
      'description' => '',
      'category' => [
        $this->categories['integer_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];
    $attribute = EavAttribute::create($attribute_values);
    $attribute->save();

    // Check if attribute has been created
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'tr[data-drupal-selector="edit-eav-attributes-' . $attribute->id() . '"]');

    // Attribute form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.edit_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('value_type', $attribute_values['value_type']);
    $this->web_assert->fieldValueEquals('value_widget_type', $attribute_values['value_widget_type']);
    $this->web_assert->fieldValueEquals('value_formatter_type', $attribute_values['value_formatter_type']);

    // Storage settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_storage_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('cardinality', 'number');
    $this->web_assert->fieldValueEquals('cardinality_number', $attribute_values['value_storage_config']['cardinality']);

    // Field settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_field_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('settings[min]', $attribute_values['value_config']['settings']['min']);
    $this->web_assert->fieldValueEquals('settings[max]', $attribute_values['value_config']['settings']['max']);
    $this->web_assert->fieldValueEquals('settings[prefix]', $attribute_values['value_config']['settings']['prefix']);
    $this->web_assert->fieldValueEquals('settings[suffix]', $attribute_values['value_config']['settings']['suffix']);
    $this->web_assert->fieldValueEquals('default_value_input[integer_value][0][value]', '');

    // Widget settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_widget_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('fields[integer_value][settings_edit_form][settings][placeholder]', '');

    // Formatter settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_formatter_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('fields[integer_value][settings_edit_form][settings][thousand_separator]', ' ');
    $this->web_assert->checkboxChecked('fields[integer_value][settings_edit_form][settings][prefix_suffix]');
  }

  private function _testAddAttributeFromCode_Decimal(): void {
    $attribute_values = [
      'label' => 'Decimal attribute',
      'machine_name' => 'decimal_attr',
      'value_type' => 'decimal',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [
          'precision' => 10,
          'scale' => 2,
        ],
      ],
      'value_config' => [
        'description' => '',
        'required' => FALSE,
        'default_value' => [],
        'settings' => [
          'min' => '-10',
          'max' => '300',
          'prefix' => '$',
          'suffix' => '',
        ],
      ],
      'value_widget_type' => 'number',
      'value_widget_settings' => [
        'placeholder' => '',
      ],
      'value_formatter_type' => 'number_decimal',
      'value_formatter_settings' => [
        'thousand_separator' => ' ',
        'decimal_separator' => '.',
        'scale' => 2,
        'prefix_suffix' => TRUE,
      ],
      'description' => '',
      'category' => [
        $this->categories['decimal_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];
    $attribute = EavAttribute::create($attribute_values);
    $attribute->save();

    // Check if attribute has been created
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'tr[data-drupal-selector="edit-eav-attributes-' . $attribute->id() . '"]');

    // Attribute form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.edit_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('value_type', $attribute_values['value_type']);
    $this->web_assert->fieldValueEquals('value_widget_type', $attribute_values['value_widget_type']);
    $this->web_assert->fieldValueEquals('value_formatter_type', $attribute_values['value_formatter_type']);

    // Storage settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_storage_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('cardinality', 'number');
    $this->web_assert->fieldValueEquals('cardinality_number', $attribute_values['value_storage_config']['cardinality']);
    $this->web_assert->fieldValueEquals('settings[precision]', $attribute_values['value_storage_config']['settings']['precision']);
    $this->web_assert->fieldValueEquals('settings[scale]', $attribute_values['value_storage_config']['settings']['scale']);

    // Field settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_field_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('settings[min]', $attribute_values['value_config']['settings']['min']);
    $this->web_assert->fieldValueEquals('settings[max]', $attribute_values['value_config']['settings']['max']);
    $this->web_assert->fieldValueEquals('settings[prefix]', $attribute_values['value_config']['settings']['prefix']);
    $this->web_assert->fieldValueEquals('settings[suffix]', $attribute_values['value_config']['settings']['suffix']);
    $this->web_assert->fieldValueEquals('default_value_input[decimal_value][0][value]', '');

    // Widget settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_widget_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('fields[decimal_value][settings_edit_form][settings][placeholder]', $attribute_values['value_widget_settings']['placeholder']);

    // Formatter settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_formatter_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('fields[decimal_value][settings_edit_form][settings][thousand_separator]', $attribute_values['value_formatter_settings']['thousand_separator']);
    $this->web_assert->fieldValueEquals('fields[decimal_value][settings_edit_form][settings][decimal_separator]', $attribute_values['value_formatter_settings']['decimal_separator']);
    $this->web_assert->fieldValueEquals('fields[decimal_value][settings_edit_form][settings][scale]', $attribute_values['value_formatter_settings']['scale']);
    $this->web_assert->checkboxChecked('fields[decimal_value][settings_edit_form][settings][prefix_suffix]');
  }

  private function _testAddAttributeFromCode_Boolean(): void {
    $attribute_values = [
      'label' => 'Boolean attribute',
      'machine_name' => 'boolean_attr',
      'value_type' => 'boolean',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [],
      ],
      'value_config' => [
        'description' => '',
        'required' => FALSE,
        'default_value' => [
          0 => [
            'value' => 0,
          ],
        ],
        'settings' => [
          'on_label' => 'Yes',
          'off_label' => 'No',
        ],
      ],
      'value_widget_type' => 'boolean_checkbox',
      'value_widget_settings' => [
        'display_label' => TRUE,
      ],
      'value_formatter_type' => 'boolean',
      'value_formatter_settings' => [
        'format' => 'default',
        'format_custom_true' => '',
        'format_custom_false' => '',
      ],
      'description' => '',
      'category' => [
        $this->categories['boolean_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];
    $attribute = EavAttribute::create($attribute_values);
    $attribute->save();

    // Check if attribute has been created
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'tr[data-drupal-selector="edit-eav-attributes-' . $attribute->id() . '"]');

    // Edit attribute form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.edit_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('value_type', $attribute_values['value_type']);
    $this->web_assert->fieldValueEquals('value_widget_type', $attribute_values['value_widget_type']);
    $this->web_assert->fieldValueEquals('value_formatter_type', $attribute_values['value_formatter_type']);

    // Storage settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_storage_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('cardinality', 'number');
    $this->web_assert->fieldValueEquals('cardinality_number', $attribute_values['value_storage_config']['cardinality']);

    // Field settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_field_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('settings[on_label]', $attribute_values['value_config']['settings']['on_label']);
    $this->web_assert->fieldValueEquals('settings[off_label]', $attribute_values['value_config']['settings']['off_label']);
    $this->web_assert->checkboxNotChecked('default_value_input[boolean_value][value]');

    // Widget settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_widget_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->checkboxChecked('fields[boolean_value][settings_edit_form][settings][display_label]');

    // Formatter settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_formatter_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('fields[boolean_value][settings_edit_form][settings][format]', 'default');
  }

  private function _testAddAttributeFromCode_EntityReference(): void {
    $attribute_values = [
      'label' => 'Entity reference attribute',
      'machine_name' => 'entity_reference_attr',
      'value_type' => 'entity_reference',
      'value_widget_type' => 'options_select',
      'value_formatter_type' => 'entity_reference_label',
      'description' => '',
      'category' => [
        $this->categories['entity_reference_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];
    $attribute = EavAttribute::create($attribute_values);
    $attribute->save();

    // Check if attribute has been created
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'tr[data-drupal-selector="edit-eav-attributes-' . $attribute->id() . '"]');

    // Storage settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_storage_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldExists('settings[target_type]');
    $this->web_assert->fieldExists('cardinality');
    $this->web_assert->fieldExists('cardinality_number');
    $this->submitForm([
      'settings[target_type]' => 'taxonomy_term',
    ], 'Continue');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('settings[target_type]', 'taxonomy_term');
    $this->web_assert->fieldValueEquals('cardinality', 'number');
    $this->web_assert->fieldValueEquals('cardinality_number', '1');

    // Field settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_field_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldExists('settings[handler]');
    $this->web_assert->fieldExists('settings[handler_settings][target_bundles][category]');
    $this->web_assert->fieldExists('default_value_input[entity_reference_value][0][target_id]');
    $this->submitForm([
      'settings[handler_settings][target_bundles][category]' => 'category',
    ], 'Save settings');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('settings[handler]', 'default:taxonomy_term');
    $this->web_assert->checkboxNotChecked('settings[handler_settings][auto_create]');
    $this->web_assert->checkboxChecked('settings[handler_settings][target_bundles][category]');
    $this->web_assert->fieldValueEquals('default_value_input[entity_reference_value][0][target_id]', '');

    // Widget settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_widget_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->pageTextContains('No settings.');

    // Formatter settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_formatter_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldExists('fields[entity_reference_value][settings_edit_form][settings][link]');
    $this->web_assert->checkboxChecked('fields[entity_reference_value][settings_edit_form][settings][link]');
    $this->submitForm([
      'fields[entity_reference_value][settings_edit_form][settings][link]' => FALSE,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldExists('fields[entity_reference_value][settings_edit_form][settings][link]');
    $this->web_assert->checkboxNotChecked('fields[entity_reference_value][settings_edit_form][settings][link]');
  }

  private function _testAddAttributeFromCode_ListString(): void {
    $attribute_values = [
      'label' => 'List string attribute',
      'machine_name' => 'list_string_attr',
      'value_type' => 'list_string',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [
          'allowed_values' => [
            'foo' => 'Foo',
            'bar' => 'Bar',
            'baz' => 'Baz',
          ],
          'allowed_values_function' => '',
        ],
      ],
      'value_config' => [
        'description' => '',
        'required' => FALSE,
        'default_value' => [
          0 => [
            'value' => 'bar',
          ],
        ],
        'settings' => [],
      ],
      'value_widget_type' => 'options_select',
      'value_widget_settings' => [],
      'value_formatter_type' => 'list_default',
      'value_formatter_settings' => [],
      'description' => '',
      'category' => [
        $this->categories['list_string_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];
    $attribute = EavAttribute::create($attribute_values);
    $attribute->save();

    // Check if attribute has been created
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'tr[data-drupal-selector="edit-eav-attributes-' . $attribute->id() . '"]');

    // Check attribute form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.edit_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('value_type', $attribute_values['value_type']);
    $this->web_assert->fieldValueEquals('value_widget_type', $attribute_values['value_widget_type']);
    $this->web_assert->fieldValueEquals('value_formatter_type', $attribute_values['value_formatter_type']);

    // Check storage settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_storage_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('cardinality', 'number');
    $this->web_assert->fieldValueEquals('cardinality_number', $attribute_values['value_storage_config']['cardinality']);
    $this->web_assert->fieldValueEquals('settings[allowed_values][table][0][item][key]', 'foo');
    $this->web_assert->fieldValueEquals('settings[allowed_values][table][0][item][label]', 'Foo');
    $this->web_assert->fieldValueEquals('settings[allowed_values][table][1][item][key]', 'bar');
    $this->web_assert->fieldValueEquals('settings[allowed_values][table][1][item][label]', 'Bar');

    // Check field settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_field_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldExists('default_value_input[list_string_value]');
    $this->web_assert->fieldValueEquals('default_value_input[list_string_value]', $attribute_values['value_config']['default_value'][0]['value']);

    // Check widget settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_widget_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->pageTextContains('No settings.');

    // Check formatter settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_formatter_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->pageTextContains('No settings.');
  }

  private function _testAddAttributeFromCode_ListInteger(): void {
    $attribute_values = [
      'label' => 'List integer attribute',
      'machine_name' => 'list_integer_attr',
      'value_type' => 'list_integer',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [
          'allowed_values' => [
            1 => 'Foo',
            2 => 'Bar',
            3 => 'Baz',
          ],
          'allowed_values_function' => '',
        ],
      ],
      'value_config' => [
        'description' => '',
        'required' => FALSE,
        'default_value' => [],
        'settings' => [],
      ],
      'value_widget_type' => 'options_select',
      'value_widget_settings' => [],
      'value_formatter_type' => 'list_default',
      'value_formatter_settings' => [],
      'description' => '',
      'category' => [
        $this->categories['list_integer_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];
    $attribute = EavAttribute::create($attribute_values);
    $attribute->save();

    // Check if attribute has been created
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'tr[data-drupal-selector="edit-eav-attributes-' . $attribute->id() . '"]');

    // Check attribute form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.edit_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('value_type', $attribute_values['value_type']);
    $this->web_assert->fieldValueEquals('value_widget_type', $attribute_values['value_widget_type']);
    $this->web_assert->fieldValueEquals('value_formatter_type', $attribute_values['value_formatter_type']);

    // Check Storage settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_storage_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('cardinality', 'number');
    $this->web_assert->fieldValueEquals('cardinality_number', '1');
    $this->web_assert->fieldValueEquals('settings[allowed_values][table][0][item][key]', '1');
    $this->web_assert->fieldValueEquals('settings[allowed_values][table][0][item][label]', 'Foo');
    $this->web_assert->fieldValueEquals('settings[allowed_values][table][1][item][key]', '2');
    $this->web_assert->fieldValueEquals('settings[allowed_values][table][1][item][label]', 'Bar');

    // Check Field settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_field_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldExists('default_value_input[list_integer_value]');

    // Check Widget settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_widget_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->pageTextContains('No settings.');

    // Check Formatter settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_formatter_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->pageTextContains('No settings.');
  }

  private function _testAddAttributeFromCode_Simple(): void {
    $attribute_values = [
      'label' => 'Simple attribute',
      'machine_name' => 'simple_attr',
      'category' => [
        $this->categories['simple_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];
    $attribute = EavAttribute::create($attribute_values);
    $attribute->save();

    // Attributes list
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'tr[data-drupal-selector="edit-eav-attributes-' . $attribute->id() . '"]');

    // Attribute edit form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.edit_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('label[0][value]', $attribute_values['label']);
    $this->web_assert->fieldValueEquals('machine_name[0][value]', $attribute_values['machine_name']);
    $this->web_assert->fieldValueEquals('value_type', 'string');
    $this->web_assert->fieldValueEquals('value_widget_type', 'string_textfield');
    $this->web_assert->fieldValueEquals('value_formatter_type', '_none');
    $this->web_assert->checkboxChecked('category[' . $attribute_values['category'][0] . ']');
    $this->web_assert->checkboxChecked('category[' . $attribute_values['category'][1] . ']');
    $this->web_assert->fieldValueEquals('description[0][value]', '');

    // Storage settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_storage_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('settings[max_length]', 255);
    $this->web_assert->fieldValueEquals('cardinality', 'number');
    $this->web_assert->fieldValueEquals('cardinality_number', 1);

    // Field settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_field_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('description', '');
    $this->web_assert->fieldValueEquals('default_value_input[string_value][0][value]', '');

    // Widget settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_widget_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('fields[string_value][settings_edit_form][settings][size]', 60);
    $this->web_assert->fieldValueEquals('fields[string_value][settings_edit_form][settings][placeholder]', '');

    // Formatter form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_formatter_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->pageTextContains('No settings.');
  }

  private function _testAddAttributeFromCode_MultiString(): void {
    $attribute_values = [
      'label' => 'Multi string attribute',
      'machine_name' => 'multi_string_attr',
      'value_type' => 'string',
      'value_storage_config' => [
        'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
        'settings' => [
          'max_length' => 250,
        ],
      ],
      'value_config' => [
        'description' => '',
        'required' => FALSE,
        'default_value' => [],
        'settings' => [],
      ],
      'value_widget_type' => 'string_textfield',
      'value_widget_settings' => [
        'size' => 60,
        'placeholder' => '',
      ],
      'value_formatter_type' => 'string',
      'value_formatter_settings' => [
        'link_to_entity' => FALSE,
      ],
      'description' => '',
      'category' => [
        $this->categories['multi_string_attr']->id(),
        $this->categories['string_and_multi_string_attr']->id(),
        $this->categories['all']->id(),
      ],
    ];
    $attribute = EavAttribute::create($attribute_values);
    $attribute->save();

    // Check Check if attribute has been created
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'tr[data-drupal-selector="edit-eav-attributes-' . $attribute->id() . '"]');

    // Check Storage settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_storage_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('settings[max_length]', $attribute_values['value_storage_config']['settings']['max_length']);
    $this->web_assert->fieldValueEquals('cardinality', $attribute_values['value_storage_config']['cardinality']);

    // Check Field settings form
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_field_form', ['eav_attribute' => $attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('description', $attribute_values['value_config']['description']);
  }


  private function _testAttributesList(): void {
    $attribute_values = [
      'label' => 'String attribute',
      'machine_name' => 'string_attr3',
      'value_type' => 'string',
      'value_storage_config' => [
        'cardinality' => 1,
        'settings' => [
          'max_length' => 210,
        ],
      ],
      'value_config' => [
        'description' => '',
        'required' => FALSE,
        'default_value' => [],
        'settings' => [],
      ],
      'value_widget_type' => 'string_textfield',
      'value_widget_settings' => [
        'size' => 40,
        'placeholder' => '',
      ],
      'value_formatter_type' => 'string',
      'value_formatter_settings' => [
        'link_to_entity' => FALSE,
      ],
      'description' => '',
      'category' => [
        $this->categories['all']->id(),
      ],
    ];
    $attribute = EavAttribute::create($attribute_values);
    $attribute->save();

    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->dontSeeErrorMessage();
    $attribute_tr_selector = 'tr[data-drupal-selector="edit-eav-attributes-' . $attribute->id() . '"]';
    $this->web_assert->elementExists('css', $attribute_tr_selector);
    $this->web_assert->elementExists('css', $attribute_tr_selector . ' ul.dropbutton a[href^="/admin/structure/eav/attributes/' . $attribute->id() . '/edit"]');
    $this->web_assert->elementExists('css', $attribute_tr_selector . ' ul.dropbutton a[href^="/admin/structure/eav/attributes/' . $attribute->id() . '/storage"]');
    $this->web_assert->elementExists('css', $attribute_tr_selector . ' ul.dropbutton a[href^="/admin/structure/eav/attributes/' . $attribute->id() . '/field"]');
    $this->web_assert->elementExists('css', $attribute_tr_selector . ' ul.dropbutton a[href^="/admin/structure/eav/attributes/' . $attribute->id() . '/widget"]');
    $this->web_assert->elementExists('css', $attribute_tr_selector . ' ul.dropbutton a[href^="/admin/structure/eav/attributes/' . $attribute->id() . '/formatter"]');
    $this->web_assert->elementExists('css', $attribute_tr_selector . ' ul.dropbutton a[href^="/admin/structure/eav/attributes/' . $attribute->id() . '/delete"]');
  }

  private function _testAttributesListFormSubmit(): void {
    $list_string_attribute = EavAttribute::loadByMachineName('list_string_attr');
    $list_integer_attribute = EavAttribute::loadByMachineName('list_integer_attr');

    $this->drupalGet(Url::fromRoute('entity.eav_attribute.collection'));
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('eav_attributes[' . $list_string_attribute->id() . '][weight]', $list_string_attribute->getWeight());
    $this->web_assert->fieldValueEquals('eav_attributes[' . $list_integer_attribute->id() . '][weight]', $list_integer_attribute->getWeight());

    $this->submitForm([
      'eav_attributes[' . $list_string_attribute->id() . '][weight]' => 100,
      'eav_attributes[' . $list_integer_attribute->id() . '][weight]' => 99,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('eav_attributes[' . $list_string_attribute->id() . '][weight]', 100);
    $this->web_assert->fieldValueEquals('eav_attributes[' . $list_integer_attribute->id() . '][weight]', 99);
  }


  private function _testAttributesValuesFormBuilder_String(): void {
    $attribute = EavAttribute::loadByMachineName('string_attr');
    $attribute_value_storage_config_array = $attribute->getValueStorageConfigArray();
    $attribute_value_config_array = $attribute->getValueConfigArray();
    $attribute_value_widget_settings = $attribute->getValueWidgetSettings();

    $this->drupalGet(Url::fromRoute('node.add', ['node_type' => 'product']));
    $this->dontSeeErrorMessage();
    $this->submitForm([
      'title[0][value]' => 'Product for ' . __FUNCTION__,
      'field_category' => $this->categories['string_attr']->id(),
    ], 'Save');
    $this->dontSeeErrorMessage();

    $node = $this->getLastAddedNode('product');
    $this->drupalGetEntityPage($node);
    $this->dontSeeErrorMessage();
    $edit_eav_page_url = $this->getEntityEavFormUrl($node->id());
    $this->web_assert->elementExists('css', '#block-local-tasks-block a[href="' . $edit_eav_page_url->toString() . '"]');

    $this->drupalGet($edit_eav_page_url);
    $this->dontSeeErrorMessage();
    $this->web_assert->elementsCount('css', 'tbody tr', 1);
    $this->web_assert->elementExists('css', 'input[type="text"][name="field_eav[string_attr][string_value][0][value]"]');
    $this->web_assert->fieldValueEquals('field_eav[string_attr][string_value][0][value]', $attribute_value_config_array['default_value'][0]['value']);
    $this->web_assert->elementTextContains('css', '#edit-field-eav-string-attr-string-value-0-value--description', $attribute_value_config_array['description']);
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-string-attr-string-value-0-value', 'size', $attribute_value_widget_settings['size']);
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-string-attr-string-value-0-value', 'maxlength', $attribute_value_storage_config_array['settings']['max_length']);
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-string-attr-string-value-0-value', 'placeholder', $attribute_value_widget_settings['placeholder']);
    $this->web_assert->elementExists('css', '.eav-entity-attributes-form .form-actions .form-submit');

    $node->delete();
  }

  private function _testAttributesValuesFormBuilder_StringLong(): void {
    $attribute = EavAttribute::loadByMachineName('string_long_attr');
    $attribute_widget_settings = $attribute->getValueWidgetSettings();

    $node = $this->createProductNode($this->categories['string_long_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $this->web_assert->elementsCount('css', 'tbody tr', 1);
    $this->web_assert->elementExists('css', 'textarea[name="field_eav[string_long_attr][string_long_value][0][value]"]');
    $this->web_assert->fieldValueEquals('field_eav[string_long_attr][string_long_value][0][value]', '');
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-string-long-attr-string-long-value-0-value', 'rows', $attribute_widget_settings['rows']);
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-string-long-attr-string-long-value-0-value', 'placeholder', $attribute_widget_settings['placeholder']);

    $node->delete();
  }

  private function _testAttributesValuesFormBuilder_Integer(): void {
    $attribute = EavAttribute::loadByMachineName('integer_attr');
    $attribute_value_config_array = $attribute->getValueConfigArray();

    $node = $this->createProductNode($this->categories['integer_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $this->web_assert->elementExists('css', 'input[type="number"][name="field_eav[integer_attr][integer_value][0][value]"]');
    $this->web_assert->elementTextContains('css', '.form-item-field-eav-integer-attr-integer-value-0-value .field-suffix', $attribute_value_config_array['settings']['suffix']);
    $this->web_assert->elementNotExists('css', '.form-item-field-eav-integer-attr-integer-value-0-value .field-prefix');

    $node->delete();
  }

  private function _testAttributesValuesFormBuilder_Decimal(): void {
    $attribute = EavAttribute::loadByMachineName('decimal_attr');
    $attribute_value_config_array = $attribute->getValueConfigArray();

    $node = $this->createProductNode($this->categories['decimal_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $this->web_assert->elementExists('css', 'input[type="number"][name="field_eav[decimal_attr][decimal_value][0][value]"]');
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-decimal-attr-decimal-value-0-value', 'min', $attribute_value_config_array['settings']['min']);
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-decimal-attr-decimal-value-0-value', 'max', $attribute_value_config_array['settings']['max']);
    $this->web_assert->elementTextContains('css', '.form-item-field-eav-decimal-attr-decimal-value-0-value .field-prefix', $attribute_value_config_array['settings']['prefix']);
    $this->web_assert->elementNotExists('css', '.form-item-field-eav-decimal-attr-decimal-value-0-value .field-suffix');

    $node->delete();
  }

  private function _testAttributesValuesFormBuilder_Boolean(): void {
    $node = $this->createProductNode($this->categories['boolean_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $this->web_assert->elementExists('css', 'input[type="checkbox"][name="field_eav[boolean_attr][boolean_value][value]"]');
    $this->web_assert->checkboxNotChecked('field_eav[boolean_attr][boolean_value][value]');

    $node->delete();
  }

  private function _testAttributesValuesFormBuilder_EntityReference(): void {

    $node = $this->createProductNode($this->categories['entity_reference_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $this->web_assert->elementExists('css', 'select[name="field_eav[entity_reference_attr][entity_reference_value]"]');
    $this->web_assert->elementExists('css', '#edit-field-eav-entity-reference-attr-entity-reference-value option[value="1"]');

    $node->delete();
  }

  private function _testAttributesValuesFormBuilder_ListInteger(): void {
    $node = $this->createProductNode($this->categories['list_integer_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $this->web_assert->elementExists('css', 'select[name="field_eav[list_integer_attr][list_integer_value]"]');
    $this->web_assert->elementExists('css', '#edit-field-eav-list-integer-attr-list-integer-value option[value="1"]');
    $this->web_assert->elementExists('css', '#edit-field-eav-list-integer-attr-list-integer-value option[value="2"]');

    $node->delete();
  }

  private function _testAttributesValuesFormBuilder_ListString(): void {
    $node = $this->createProductNode($this->categories['list_string_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $this->web_assert->elementExists('css', 'select[name="field_eav[list_string_attr][list_string_value]"]');
    $this->web_assert->elementExists('css', '#edit-field-eav-list-string-attr-list-string-value option[value="foo"]');
    $this->web_assert->elementExists('css', '#edit-field-eav-list-string-attr-list-string-value option[value="bar"]');
    $this->web_assert->fieldValueEquals('field_eav[list_string_attr][list_string_value]', 'bar');

    $node->delete();
  }

  private function _testAttributesValuesFormBuilder_Simple(): void {
    $node = $this->createProductNode($this->categories['simple_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $this->web_assert->elementExists('css', 'input[name="field_eav[simple_attr][string_value][0][value]"][type="text"]');
    $this->web_assert->fieldValueEquals('field_eav[simple_attr][string_value][0][value]', '');

    $node->delete();
  }

  private function _testAttributesValuesFormBuilder_MultiString(): void {
    $node = $this->createProductNode($this->categories['multi_string_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $this->web_assert->elementExists('css', 'input[name="field_eav[multi_string_attr][string_value][0][value]"][type="text"]');
    $this->web_assert->elementExists('css', 'select[name="field_eav[multi_string_attr][string_value][0][_weight]"]');
    $this->web_assert->elementExists('css', 'input[type="submit"][value="Add another item"]');
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][0][value]', '');

    $node->delete();
  }

  private function _testAttributesValuesFormBuilder_StringAndMultiString(): void {
    $string_attr = EavAttribute::loadByMachineName('string_attr');
    $string_attr_value_config = $string_attr->getValueConfigArray();
    $string_attr_value_storage_config = $string_attr->getValueStorageConfigArray();
    $string_attr_widget_settings = $string_attr->getValueWidgetSettings();

    $multi_string_attr = EavAttribute::loadByMachineName('multi_string_attr');
    $multi_string_attr_value_storage_config = $multi_string_attr->getValueStorageConfigArray();
    $multi_string_attr_widget_settings = $multi_string_attr->getValueWidgetSettings();

    $node = $this->createProductNode($this->categories['string_and_multi_string_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-string-attr-string-value-0-value', 'type', 'text');
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-string-attr-string-value-0-value', 'size', $string_attr_widget_settings['size']);
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-string-attr-string-value-0-value', 'maxlength', $string_attr_value_storage_config['settings']['max_length']);
    $this->web_assert->elementNotExists('css', '#edit-field-eav-string-attr-string-value-1-value');
    $this->web_assert->fieldValueEquals('field_eav[string_attr][string_value][0][value]', $string_attr->getValueFieldDefaultValues()[0]['value']);
    $this->web_assert->elementContains('css', '#edit-field-eav-string-attr-string-value-0-value--description', $string_attr_value_config['description']);

    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-multi-string-attr-string-value-0-value', 'type', 'text');
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-multi-string-attr-string-value-0-value', 'size', $multi_string_attr_widget_settings['size']);
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-multi-string-attr-string-value-0-value', 'maxlength', $multi_string_attr_value_storage_config['settings']['max_length']);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][0][value]', '');
    $this->web_assert->elementExists('css', 'select[name="field_eav[multi_string_attr][string_value][0][_weight]"]');
    $this->web_assert->elementExists('css', 'input[type="submit"][value="Add another item"]');
    $this->web_assert->elementNotExists('css', 'tr[data-drupal-selector="edit-field-eav-multi-string-attr"] .description');
    $this->web_assert->elementNotExists('css', '#edit-field-eav-multi-string-attr-string-value-1-value');

    $node->delete();
  }

  private function _testAttributesValuesFormBuilder_MultiStringAndString(): void {
    $string_attr = EavAttribute::loadByMachineName('string_attr');
    $string_attr_value_config = $string_attr->getValueConfigArray();
    $string_attr_value_storage_config = $string_attr->getValueStorageConfigArray();
    $string_attr_widget_settings = $string_attr->getValueWidgetSettings();

    $multi_string_attr = EavAttribute::loadByMachineName('multi_string_attr');
    $multi_string_attr_value_storage_config = $multi_string_attr->getValueStorageConfigArray();
    $multi_string_attr_widget_settings = $multi_string_attr->getValueWidgetSettings();

    $multi_string_attr_weight = $multi_string_attr->getWeight();
    $multi_string_attr->setWeight(-100)->save();

    $node = $this->createProductNode($this->categories['string_and_multi_string_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-string-attr-string-value-0-value', 'type', 'text');
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-string-attr-string-value-0-value', 'size', $string_attr_widget_settings['size']);
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-string-attr-string-value-0-value', 'maxlength', $string_attr_value_storage_config['settings']['max_length']);
    $this->web_assert->elementNotExists('css', '#edit-field-eav-string-attr-string-value-1-value');
    $this->web_assert->fieldValueEquals('field_eav[string_attr][string_value][0][value]', $string_attr->getValueFieldDefaultValues()[0]['value']);
    $this->web_assert->elementContains('css', '#edit-field-eav-string-attr-string-value-0-value--description', $string_attr_value_config['description']);

    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-multi-string-attr-string-value-0-value', 'type', 'text');
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-multi-string-attr-string-value-0-value', 'size', $multi_string_attr_widget_settings['size']);
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-multi-string-attr-string-value-0-value', 'maxlength', $multi_string_attr_value_storage_config['settings']['max_length']);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][0][value]', '');
    $this->web_assert->elementExists('css', 'select[name="field_eav[multi_string_attr][string_value][0][_weight]"]');
    $this->web_assert->elementExists('css', 'input[type="submit"][value="Add another item"]');
    $this->web_assert->elementNotExists('css', 'tr[data-drupal-selector="edit-field-eav-multi-string-attr"] .description');
    $this->web_assert->elementNotExists('css', '#edit-field-eav-multi-string-attr-string-value-1-value');

    $node->delete();
    $multi_string_attr->setWeight($multi_string_attr_weight)->save();
  }

  private function _testAttributesValuesFormBuilder_AllAttributes(): void {
    $node = $this->createProductNode($this->categories['all']->id());
    $this->drupalGetEavFormPage($node->id());

    // Check String attribute
    $string_attr = EavAttribute::loadByMachineName('string_attr');
    $string_attr_value_storage_config = $string_attr->getValueStorageConfigArray();
    $string_attr_value_config = $string_attr->getValueConfigArray();
    $string_attr_value_widget_settings = $string_attr->getValueWidgetSettings();
    $string_attr_input_selector = '#edit-field-eav-string-attr-string-value-0-value';
    $this->web_assert->elementAttributeContains('css', $string_attr_input_selector, 'type', 'text');
    $this->web_assert->elementAttributeContains('css', $string_attr_input_selector, 'size', $string_attr_value_widget_settings['size']);
    $this->web_assert->elementAttributeContains('css', $string_attr_input_selector, 'maxlength', $string_attr_value_storage_config['settings']['max_length']);
    $this->web_assert->elementAttributeContains('css', $string_attr_input_selector, 'placeholder', $string_attr_value_widget_settings['placeholder']);
    $this->web_assert->elementAttributeContains('css', $string_attr_input_selector, 'value', $string_attr_value_config['default_value'][0]['value']);
    $this->web_assert->elementTextContains('css', $string_attr_input_selector . '--description', $string_attr_value_config['description']);

    // Check Second string attribute
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-second-string-attr-string-value-0-value', 'type', 'text');
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-second-string-attr-string-value-0-value', 'value', '');
    $this->web_assert->elementExists('css', '.form-item-field-eav-second-string-attr-string-value-0-value');
    $this->web_assert->elementNotExists('css', '.form-item-field-eav-second-string-attr-string-value-0-value .description');

    // Check String long attribute
    $string_long_attr = EavAttribute::loadByMachineName('string_long_attr');
    $string_long_attr_widget_settings = $string_long_attr->getValueWidgetSettings();
    $this->web_assert->elementExists('css', 'textarea[name="field_eav[string_long_attr][string_long_value][0][value]"]');
    $this->web_assert->fieldValueEquals('field_eav[string_long_attr][string_long_value][0][value]', '');
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-string-long-attr-string-long-value-0-value', 'rows', $string_long_attr_widget_settings['rows']);
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-string-long-attr-string-long-value-0-value', 'placeholder', $string_long_attr_widget_settings['placeholder']);

    // Check Integer attribute
    $integer_attr = EavAttribute::loadByMachineName('integer_attr');
    $integer_attr_value_config = $integer_attr->getValueConfigArray();
    $this->web_assert->elementAttributeContains('css', 'input[name="field_eav[integer_attr][integer_value][0][value]"]', 'type', 'number');
    $this->web_assert->elementExists('css', '.form-item-field-eav-integer-attr-integer-value-0-value');
    $this->web_assert->elementTextContains('css', '.form-item-field-eav-integer-attr-integer-value-0-value .field-suffix', $integer_attr_value_config['settings']['suffix']);
    $this->web_assert->elementNotExists('css', '.form-item-field-eav-integer-attr-integer-value-0-value .field-prefix');

    // Check Decimal attribute
    $decimal_attr = EavAttribute::loadByMachineName('decimal_attr');
    $decimal_attr_value_config = $decimal_attr->getValueConfigArray();
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-decimal-attr-decimal-value-0-value', 'type', 'number');
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-decimal-attr-decimal-value-0-value', 'min', $decimal_attr_value_config['settings']['min']);
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-decimal-attr-decimal-value-0-value', 'max', $decimal_attr_value_config['settings']['max']);
    $this->web_assert->elementTextContains('css', '.form-item-field-eav-decimal-attr-decimal-value-0-value .field-prefix', $decimal_attr_value_config['settings']['prefix']);
    $this->web_assert->elementNotExists('css', '.form-item-field-eav-decimal-attr-decimal-value-0-value .field-suffix');

    // Check Boolean attribute
    $this->web_assert->elementAttributeContains('css', 'input[name="field_eav[boolean_attr][boolean_value][value]"]', 'type', 'checkbox');
    $this->web_assert->checkboxNotChecked('field_eav[boolean_attr][boolean_value][value]');

    // Check Entity reference attribute
    $this->web_assert->selectExists('field_eav[entity_reference_attr][entity_reference_value]');
    $this->web_assert->elementExists('css', '#edit-field-eav-entity-reference-attr-entity-reference-value option[value="1"]');

    // Check List integer attribute
    $this->web_assert->selectExists('field_eav[list_integer_attr][list_integer_value]');
    $this->web_assert->elementExists('css', '#edit-field-eav-list-integer-attr-list-integer-value option[value="1"]');
    $this->web_assert->elementExists('css', '#edit-field-eav-list-integer-attr-list-integer-value option[value="2"]');

    // Check List string attribute
    $this->web_assert->selectExists('field_eav[list_string_attr][list_string_value]');
    $this->web_assert->elementExists('css', '#edit-field-eav-list-string-attr-list-string-value option[value="foo"]');
    $this->web_assert->elementExists('css', '#edit-field-eav-list-string-attr-list-string-value option[value="bar"]');
    $this->web_assert->fieldValueEquals('field_eav[list_string_attr][list_string_value]', 'bar');

    // Check Simple attribute
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-simple-attr-string-value-0-value', 'type', 'text');
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-simple-attr-string-value-0-value', 'value', '');
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-simple-attr-string-value-0-value', 'size', 60);
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-simple-attr-string-value-0-value', 'maxlength', 255);
    $this->web_assert->elementAttributeContains('css', '#edit-field-eav-simple-attr-string-value-0-value', 'placeholder', '');
    $this->web_assert->elementExists('css', '.form-item-field-eav-simple-attr-string-value-0-value');
    $this->web_assert->elementNotExists('css', '.form-item-field-eav-simple-attr-string-value-0-value .field-prefix');
    $this->web_assert->elementNotExists('css', '.form-item-field-eav-simple-attr-string-value-0-value .field-suffix');
    $this->web_assert->elementNotExists('css', '.form-item-field-eav-simple-attr-string-value-0-value .description');

    // Check Multi string attribute
    $multi_string_attr = EavAttribute::loadByMachineName('multi_string_attr');
    $multi_string_attr_value_storage_config = $multi_string_attr->getValueStorageConfigArray();
    $multi_string_attr_value_widget_settings = $multi_string_attr->getValueWidgetSettings();
    $multi_string_attr_input_selector = '#edit-field-eav-multi-string-attr-string-value-0-value';
    $this->web_assert->elementAttributeContains('css', $multi_string_attr_input_selector, 'type', 'text');
    $this->web_assert->elementAttributeContains('css', $multi_string_attr_input_selector, 'value', '');
    $this->web_assert->elementAttributeContains('css', $multi_string_attr_input_selector, 'size', $multi_string_attr_value_widget_settings['size']);
    $this->web_assert->elementAttributeContains('css', $multi_string_attr_input_selector, 'maxlength', $multi_string_attr_value_storage_config['settings']['max_length']);
    $this->web_assert->elementAttributeContains('css', $multi_string_attr_input_selector, 'placeholder', $multi_string_attr_value_widget_settings['placeholder']);

    $this->web_assert->elementExists('css', '.eav-entity-attributes-form .form-actions .form-submit');

    $node->delete();
  }


  private function _testAttributesValuesFormSubmit_String(): void {
    $node = $this->createProductNode($this->categories['string_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    // Set value
    $attribute_value = __FUNCTION__;
    $this->submitForm([
      'field_eav[string_attr][string_value][0][value]' => $attribute_value,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->seeSystemMessage('Values saved');
    $this->web_assert->fieldValueEquals('field_eav[string_attr][string_value][0][value]', $attribute_value);
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $this->assertEquals($attribute_value, $this->getEavFieldItems($node)->getItemByAttribute('string_attr')->getValueEntity()->getValueFieldItems()->value);
    $this->assertEquals(1, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(1, $this->getDbTableRowsCount('eav_value__string_value'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value__integer_value'));

    // Change exist value
    $attribute_value = __FUNCTION__ . ' new';
    $this->submitForm([
      'field_eav[string_attr][string_value][0][value]' => $attribute_value,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->seeSystemMessage('Values saved');
    $this->web_assert->fieldValueEquals('field_eav[string_attr][string_value][0][value]', $attribute_value);
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $this->assertEquals($attribute_value, $this->getEavFieldItems($node)->getItemByAttribute('string_attr')->getValueEntity()->getValueFieldItems()->value);
    $this->assertEquals(1, $this->getDbTableRowsCount('node__field_eav'));
    $this->assertEquals(1, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(1, $this->getDbTableRowsCount('eav_value__string_value'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value__integer_value'));

    $node->delete();
    $this->assertEquals(0, $this->getDbTableRowsCount('node__field_eav'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value__string_value'));
  }

  private function _testAttributesValuesFormSubmit_StringLong(): void {
    $node = $this->createProductNode($this->categories['string_long_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $attribute_value = __FUNCTION__ . "\n" . __FUNCTION__;
    $this->submitForm([
      'field_eav[string_long_attr][string_long_value][0][value]' => $attribute_value,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('field_eav[string_long_attr][string_long_value][0][value]', $attribute_value);
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $this->assertEquals($attribute_value, $this->getEavFieldItems($node)->getItemByAttribute('string_long_attr')->getValueEntity()->getValueFieldItems()->value);

    $node->delete();
  }

  private function _testAttributesValuesFormSubmit_Integer(): void {
    $node = $this->createProductNode($this->categories['integer_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $attribute_value = '123';
    $this->submitForm([
      'field_eav[integer_attr][integer_value][0][value]' => $attribute_value,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('field_eav[integer_attr][integer_value][0][value]', $attribute_value);
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $this->assertEquals($attribute_value, $this->getEavFieldItems($node)->getItemByAttribute('integer_attr')->getValueEntity()->getValueFieldItems()->value);

    $node->delete();
  }

  private function _testAttributesValuesFormSubmit_Decimal(): void {
    $node = $this->createProductNode($this->categories['decimal_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $attribute_value = '123.12';
    $this->submitForm([
      'field_eav[decimal_attr][decimal_value][0][value]' => $attribute_value,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('field_eav[decimal_attr][decimal_value][0][value]', $attribute_value);
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $this->assertEquals($attribute_value, $this->getEavFieldItems($node)->getItemByAttribute('decimal_attr')->getValueEntity()->getValueFieldItems()->value);

    $node->delete();
  }

  private function _testAttributesValuesFormSubmit_Boolean(): void {
    $node = $this->createProductNode($this->categories['boolean_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $this->submitForm([
      'field_eav[boolean_attr][boolean_value][value]' => TRUE,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->checkboxChecked('field_eav[boolean_attr][boolean_value][value]');
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $this->assertEquals(1, $this->getEavFieldItems($node)->getItemByAttribute('boolean_attr')->getValueEntity()->getValueFieldItems()->value);

    $node->delete();
  }

  private function _testAttributesValuesFormSubmit_EntityReference(): void {
    $node = $this->createProductNode($this->categories['entity_reference_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $attribute_value = $this->categories['string_attr']->id();
    $this->submitForm([
      'field_eav[entity_reference_attr][entity_reference_value]' => $attribute_value,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('field_eav[entity_reference_attr][entity_reference_value]', $attribute_value);
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $this->assertEquals($attribute_value, $this->getEavFieldItems($node)->getItemByAttribute('entity_reference_attr')->getValueEntity()->getValueFieldItems()->target_id);

    $node->delete();
  }

  private function _testAttributesValuesFormSubmit_ListInteger(): void {
    $node = $this->createProductNode($this->categories['list_integer_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $attribute_value = 2;
    $this->submitForm([
      'field_eav[list_integer_attr][list_integer_value]' => $attribute_value,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('field_eav[list_integer_attr][list_integer_value]', $attribute_value);
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $this->assertEquals($attribute_value, $this->getEavFieldItems($node)->getItemByAttribute('list_integer_attr')->getValueEntity()->getValueFieldItems()->value);

    $node->delete();
  }

  private function _testAttributesValuesFormSubmit_ListString(): void {
    $node = $this->createProductNode($this->categories['list_string_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $attribute_value = 'bar';
    $this->submitForm([
      'field_eav[list_string_attr][list_string_value]' => $attribute_value,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('field_eav[list_string_attr][list_string_value]', $attribute_value);
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $this->assertEquals($attribute_value, $this->getEavFieldItems($node)->getItemByAttribute('list_string_attr')->getValueEntity()->getValueFieldItems()->value);

    $node->delete();
  }

  private function _testAttributesValuesFormSubmit_Simple(): void {
    $node = $this->createProductNode($this->categories['simple_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $attribute_value = __FUNCTION__;
    $this->submitForm([
      'field_eav[simple_attr][string_value][0][value]' => $attribute_value,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('field_eav[simple_attr][string_value][0][value]', $attribute_value);
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $this->assertEquals($attribute_value, $this->getEavFieldItems($node)->getItemByAttribute('simple_attr')->getValueEntity()->getValueFieldItems()->value);

    $node->delete();
  }

  private function _testAttributesValuesFormSubmit_MultiString_OneValue(): void {
    $node = $this->createProductNode($this->categories['multi_string_attr']->id());
    $this->drupalGetEavFormPage($node->id());
    $this->web_assert->fieldExists('field_eav[multi_string_attr][string_value][0][value]');
    $this->web_assert->fieldNotExists('field_eav[multi_string_attr][string_value][1][value]');

    $attribute_value = __FUNCTION__;
    $this->submitForm([
      'field_eav[multi_string_attr][string_value][0][value]' => $attribute_value,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][0][value]', $attribute_value);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][1][value]', '');
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $eav_value_entity_value_field_items = $this->getEavFieldItems($node)->getItemByAttribute('multi_string_attr')->getValueEntity()->getValueFieldItems();
    $this->assertEquals(1, $eav_value_entity_value_field_items->count());
    $this->assertEquals($attribute_value, $eav_value_entity_value_field_items[0]->value);
    $this->assertEquals(1, $this->getDbTableRowsCount('node__field_eav'));
    $this->assertEquals(1, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(1, $this->getDbTableRowsCount('eav_value__string_value'));

    $node->delete();
    $this->assertEquals(0, $this->getDbTableRowsCount('node__field_eav'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value__string_value'));
  }

  private function _testAttributesValuesFormSubmit_MultiString_ThreeValues(): void {
    $node = $this->createProductNode($this->categories['multi_string_attr']->id());
    $this->drupalGetEavFormPage($node->id());

    $this->submitForm([], 'Add another item');
    $this->dontSeeErrorMessage();
    $this->submitForm([], 'Add another item');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldExists('field_eav[multi_string_attr][string_value][0][value]');
    $this->web_assert->fieldExists('field_eav[multi_string_attr][string_value][1][value]');
    $this->web_assert->fieldExists('field_eav[multi_string_attr][string_value][2][value]');
    $this->web_assert->fieldNotExists('field_eav[multi_string_attr][string_value][3][value]');

    $attribute_value1 = __FUNCTION__ . ' 1';
    $attribute_value2 = __FUNCTION__ . ' 2';
    $attribute_value3 = __FUNCTION__ . ' 3';
    $this->submitForm([
      'field_eav[multi_string_attr][string_value][0][value]' => $attribute_value1,
      'field_eav[multi_string_attr][string_value][1][value]' => $attribute_value2,
      'field_eav[multi_string_attr][string_value][2][value]' => $attribute_value3,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][0][value]', $attribute_value1);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][1][value]', $attribute_value2);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][2][value]', $attribute_value3);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][3][value]', '');
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $eav_value_entity_value_field_items = $this->getEavFieldItems($node)->getItemByAttribute('multi_string_attr')->getValueEntity()->getValueFieldItems();
    $this->assertEquals(3, $eav_value_entity_value_field_items->count());
    $this->assertEquals($attribute_value1, $eav_value_entity_value_field_items[0]->value);
    $this->assertEquals($attribute_value2, $eav_value_entity_value_field_items[1]->value);
    $this->assertEquals($attribute_value3, $eav_value_entity_value_field_items[2]->value);
    $this->assertEquals(1, $this->getDbTableRowsCount('node__field_eav'));
    $this->assertEquals(1, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(3, $this->getDbTableRowsCount('eav_value__string_value'));

    $this->submitForm([
      'field_eav[multi_string_attr][string_value][0][value]' => '',
      'field_eav[multi_string_attr][string_value][1][value]' => $attribute_value2,
      'field_eav[multi_string_attr][string_value][2][value]' => '',
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $eav_value_entity_value_field_items = $this->getEavFieldItems($node)->getItemByAttribute('multi_string_attr')->getValueEntity()->getValueFieldItems();
    $this->assertEquals(1, $eav_value_entity_value_field_items->count());
    $this->assertEquals($attribute_value2, $eav_value_entity_value_field_items->value);
    $this->assertEquals(1, $this->getDbTableRowsCount('node__field_eav'));
    $this->assertEquals(1, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(1, $this->getDbTableRowsCount('eav_value__string_value'));

    $node->delete();
    $this->assertEquals(0, $this->getDbTableRowsCount('node__field_eav'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value__string_value'));
  }

  private function _testAttributesValuesFormSubmit_StringAndMultiString(): void {
    $node = $this->createProductNode($this->categories['string_and_multi_string_attr']->id());
    $this->drupalGetEavFormPage($node->id());
    $string_attribute_value = __FUNCTION__ . ' string';
    $multi_string_attribute_value1 = __FUNCTION__ . ' multi 1';
    $multi_string_attribute_valuw2 = __FUNCTION__ . ' multi 2';

    $this->submitForm([], 'Add another item');
    $this->submitForm([
      'field_eav[string_attr][string_value][0][value]' => $string_attribute_value,
      'field_eav[multi_string_attr][string_value][0][value]' => $multi_string_attribute_value1,
      'field_eav[multi_string_attr][string_value][1][value]' => $multi_string_attribute_valuw2,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('field_eav[string_attr][string_value][0][value]', $string_attribute_value);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][0][value]', $multi_string_attribute_value1);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][1][value]', $multi_string_attribute_valuw2);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][2][value]', '');
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $string_field_items = $this->getEavFieldItems($node)->getItemByAttribute('string_attr')->getValueEntity()->getValueFieldItems();
    $multi_string_field_items = $this->getEavFieldItems($node)->getItemByAttribute('multi_string_attr')->getValueEntity()->getValueFieldItems();
    $this->assertEquals(1, $string_field_items->count());
    $this->assertEquals(2, $multi_string_field_items->count());
    $this->assertEquals($string_attribute_value, $string_field_items->value);
    $this->assertEquals($multi_string_attribute_value1, $multi_string_field_items[0]->value);
    $this->assertEquals($multi_string_attribute_valuw2, $multi_string_field_items[1]->value);
    $this->assertEquals(2, $this->getDbTableRowsCount('node__field_eav'));
    $this->assertEquals(2, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(3, $this->getDbTableRowsCount('eav_value__string_value'));

    $node->delete();
    $this->assertEquals(0, $this->getDbTableRowsCount('node__field_eav'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value__string_value'));
  }

  private function _testAttributesValuesFormSubmit_MultiStringAndString(): void {
    $multi_string_attr = EavAttribute::loadByMachineName('multi_string_attr');
    $multi_string_attr_weight = $multi_string_attr->getWeight();
    $multi_string_attr->setWeight(-100)->save();

    $node = $this->createProductNode($this->categories['string_and_multi_string_attr']->id());
    $this->drupalGetEavFormPage($node->id());
    $multi_string_attribute_value1 = __FUNCTION__ . ' multi 1';
    $multi_string_attribute_value2 = __FUNCTION__ . ' multi 2';
    $string_attribute_value = __FUNCTION__ . ' string';

    $this->submitForm([], 'Add another item');
    $this->submitForm([
      'field_eav[multi_string_attr][string_value][0][value]' => $multi_string_attribute_value1,
      'field_eav[multi_string_attr][string_value][1][value]' => $multi_string_attribute_value2,
      'field_eav[string_attr][string_value][0][value]' => $string_attribute_value,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][0][value]', $multi_string_attribute_value1);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][1][value]', $multi_string_attribute_value2);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][2][value]', '');
    $this->web_assert->fieldValueEquals('field_eav[string_attr][string_value][0][value]', $string_attribute_value);
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $multi_string_field_items = $this->getEavFieldItems($node)->getItemByAttribute('multi_string_attr')->getValueEntity()->getValueFieldItems();
    $string_field_items = $this->getEavFieldItems($node)->getItemByAttribute('string_attr')->getValueEntity()->getValueFieldItems();
    $this->assertEquals(2, $multi_string_field_items->count());
    $this->assertEquals(1, $string_field_items->count());
    $this->assertEquals($multi_string_attribute_value1, $multi_string_field_items[0]->value);
    $this->assertEquals($multi_string_attribute_value2, $multi_string_field_items[1]->value);
    $this->assertEquals($string_attribute_value, $string_field_items->value);
    $this->assertEquals(2, $this->getDbTableRowsCount('node__field_eav'));
    $this->assertEquals(2, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(3, $this->getDbTableRowsCount('eav_value__string_value'));

    $node->delete();
    $this->assertEquals(0, $this->getDbTableRowsCount('node__field_eav'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value__string_value'));

    $multi_string_attr->setWeight($multi_string_attr_weight)->save();
  }

  private function _testAttributesValuesFormSubmit_AllAttributes(): void {
    $node = $this->createProductNode($this->categories['all']->id());
    $this->drupalGetEavFormPage($node->id());

    $form_values = [
      // Strings
      'field_eav[string_attr][string_value][0][value]' => __FUNCTION__ . ' string',
      'field_eav[second_string_attr][string_value][0][value]' => __FUNCTION__ . ' second',
      'field_eav[simple_attr][string_value][0][value]' => __FUNCTION__ . ' simple',
      'field_eav[multi_string_attr][string_value][0][value]' => __FUNCTION__ . ' multi',
      // Other
      'field_eav[string_long_attr][string_long_value][0][value]' => __FUNCTION__ . ' long',
      'field_eav[integer_attr][integer_value][0][value]' => 10,
      'field_eav[decimal_attr][decimal_value][0][value]' => 15.9,
      'field_eav[boolean_attr][boolean_value][value]' => TRUE,
      'field_eav[entity_reference_attr][entity_reference_value]' => $this->categories['entity_reference_attr']->id(),
      'field_eav[list_integer_attr][list_integer_value]' => 2,
      'field_eav[list_string_attr][list_string_value]' => 'bar',
    ];
    $this->submitForm($form_values, 'Save');
    $this->dontSeeErrorMessage();
    $this->seeSystemMessage('Values saved');

    $this->web_assert->fieldValueEquals('field_eav[string_attr][string_value][0][value]', $form_values['field_eav[string_attr][string_value][0][value]']);
    $this->web_assert->fieldValueEquals('field_eav[second_string_attr][string_value][0][value]', $form_values['field_eav[second_string_attr][string_value][0][value]']);
    $this->web_assert->fieldValueEquals('field_eav[string_long_attr][string_long_value][0][value]', $form_values['field_eav[string_long_attr][string_long_value][0][value]']);
    $this->web_assert->fieldValueEquals('field_eav[integer_attr][integer_value][0][value]', $form_values['field_eav[integer_attr][integer_value][0][value]']);
    $this->web_assert->fieldValueEquals('field_eav[decimal_attr][decimal_value][0][value]', '15.90');
    $this->web_assert->checkboxChecked('field_eav[boolean_attr][boolean_value][value]');
    $this->web_assert->fieldValueEquals('field_eav[entity_reference_attr][entity_reference_value]', $form_values['field_eav[entity_reference_attr][entity_reference_value]']);
    $this->web_assert->fieldValueEquals('field_eav[list_integer_attr][list_integer_value]', $form_values['field_eav[list_integer_attr][list_integer_value]']);
    $this->web_assert->fieldValueEquals('field_eav[list_string_attr][list_string_value]', $form_values['field_eav[list_string_attr][list_string_value]']);
    $this->web_assert->fieldValueEquals('field_eav[simple_attr][string_value][0][value]', $form_values['field_eav[simple_attr][string_value][0][value]']);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][0][value]', $form_values['field_eav[multi_string_attr][string_value][0][value]']);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][1][value]', '');

    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $this->assertEquals(11, $this->getEavFieldItems($node)->count());
    $this->assertEquals(11, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(4, $this->getDbTableRowsCount('eav_value__string_value'));
    $this->assertEquals(1, $this->getDbTableRowsCount('eav_value__integer_value'));

    $node->delete();
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value__string_value'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value__integer_value'));
  }

  private function _testAttributesValuesFormSubmitEditValues(): void {
    $node = $this->createProductNode($this->categories['all']->id());
    $this->drupalGetEavFormPage($node->id());

    $form_values = [
      'field_eav[string_attr][string_value][0][value]' => __FUNCTION__ . ' string',
      'field_eav[second_string_attr][string_value][0][value]' => __FUNCTION__ . ' second',
      'field_eav[simple_attr][string_value][0][value]' => __FUNCTION__ . ' simple',
      'field_eav[multi_string_attr][string_value][0][value]' => __FUNCTION__ . ' multi',

      'field_eav[string_long_attr][string_long_value][0][value]' => __FUNCTION__ . ' long',
      'field_eav[integer_attr][integer_value][0][value]' => 10,
      'field_eav[decimal_attr][decimal_value][0][value]' => 15.9,
      'field_eav[boolean_attr][boolean_value][value]' => TRUE,
      'field_eav[entity_reference_attr][entity_reference_value]' => $this->categories['entity_reference_attr']->id(),
      'field_eav[list_integer_attr][list_integer_value]' => 2,
      'field_eav[list_string_attr][list_string_value]' => 'bar',
    ];
    $this->submitForm($form_values, 'Save');

    $form_values = [
      'field_eav[string_attr][string_value][0][value]' => __FUNCTION__ . ' string new',
      'field_eav[second_string_attr][string_value][0][value]' => __FUNCTION__ . ' second new',
      'field_eav[simple_attr][string_value][0][value]' => __FUNCTION__ . ' simple new',
      'field_eav[multi_string_attr][string_value][0][value]' => __FUNCTION__ . ' multi new 1',
      'field_eav[multi_string_attr][string_value][1][value]' => __FUNCTION__ . ' multi new 2',

      'field_eav[string_long_attr][string_long_value][0][value]' => __FUNCTION__ . ' long new',
      'field_eav[integer_attr][integer_value][0][value]' => 1,
      'field_eav[decimal_attr][decimal_value][0][value]' => 2,
      'field_eav[boolean_attr][boolean_value][value]' => FALSE,
      'field_eav[entity_reference_attr][entity_reference_value]' => $this->categories['string_long_attr']->id(),
      'field_eav[list_integer_attr][list_integer_value]' => 3,
      'field_eav[list_string_attr][list_string_value]' => 'baz',
    ];
    $this->submitForm($form_values, 'Save');

    $this->web_assert->fieldValueEquals('field_eav[string_attr][string_value][0][value]', $form_values['field_eav[string_attr][string_value][0][value]']);
    $this->web_assert->fieldValueEquals('field_eav[second_string_attr][string_value][0][value]', $form_values['field_eav[second_string_attr][string_value][0][value]']);
    $this->web_assert->fieldValueEquals('field_eav[string_long_attr][string_long_value][0][value]', $form_values['field_eav[string_long_attr][string_long_value][0][value]']);
    $this->web_assert->fieldValueEquals('field_eav[integer_attr][integer_value][0][value]', $form_values['field_eav[integer_attr][integer_value][0][value]']);
    $this->web_assert->fieldValueEquals('field_eav[decimal_attr][decimal_value][0][value]', '2.00');
    $this->web_assert->checkboxNotChecked('field_eav[boolean_attr][boolean_value][value]');
    $this->web_assert->fieldValueEquals('field_eav[entity_reference_attr][entity_reference_value]', $form_values['field_eav[entity_reference_attr][entity_reference_value]']);
    $this->web_assert->fieldValueEquals('field_eav[list_integer_attr][list_integer_value]', $form_values['field_eav[list_integer_attr][list_integer_value]']);
    $this->web_assert->fieldValueEquals('field_eav[list_string_attr][list_string_value]', $form_values['field_eav[list_string_attr][list_string_value]']);
    $this->web_assert->fieldValueEquals('field_eav[simple_attr][string_value][0][value]', $form_values['field_eav[simple_attr][string_value][0][value]']);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][0][value]', $form_values['field_eav[multi_string_attr][string_value][0][value]']);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][1][value]', $form_values['field_eav[multi_string_attr][string_value][1][value]']);
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][2][value]', '');

    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $this->assertEquals(11, $this->getEavFieldItems($node)->count());
    $this->assertEquals(11, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(5, $this->getDbTableRowsCount('eav_value__string_value'));
    $this->assertEquals(1, $this->getDbTableRowsCount('eav_value__integer_value'));

    $node->delete();
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value__string_value'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value__integer_value'));
  }


  private function _testEavFieldFormatter(): void {
    $node = $this->createProductNode($this->categories['all']->id());
    $this->drupalGetEavFormPage($node->id());
    $form_values = [
      'field_eav[string_attr][string_value][0][value]' => __FUNCTION__ . ' string',
      'field_eav[second_string_attr][string_value][0][value]' => __FUNCTION__ . ' second',
      'field_eav[simple_attr][string_value][0][value]' => __FUNCTION__ . ' simple',
      'field_eav[multi_string_attr][string_value][0][value]' => __FUNCTION__ . ' multi',
      'field_eav[string_long_attr][string_long_value][0][value]' => __FUNCTION__ . ' long',
      'field_eav[integer_attr][integer_value][0][value]' => 11,
      'field_eav[decimal_attr][decimal_value][0][value]' => 12.60,
      'field_eav[boolean_attr][boolean_value][value]' => TRUE,
      'field_eav[entity_reference_attr][entity_reference_value]' => $this->categories['entity_reference_attr']->id(),
      'field_eav[list_integer_attr][list_integer_value]' => 1,
      'field_eav[list_string_attr][list_string_value]' => 'foo',
    ];
    $this->submitForm($form_values, 'Save');

    $this->drupalGet(Url::fromRoute('entity.node.canonical', ['node' => $node->id()]));
    $this->dontSeeErrorMessage();

    // String
    $this->web_assert->elementTextContains('css', '.eav-list__item--string-attr .eav-list__attribute-label', EavAttribute::loadByMachineName('string_attr')->label());
    $this->web_assert->elementTextContains('css', '.eav-list__item--string-attr .eav-list__value', $form_values['field_eav[string_attr][string_value][0][value]']);

    // Second string
    $this->web_assert->elementTextContains('css', '.eav-list__item--second-string-attr .eav-list__attribute-label', EavAttribute::loadByMachineName('second_string_attr')->label());
    $this->web_assert->elementTextContains('css', '.eav-list__item--second-string-attr .eav-list__value', $form_values['field_eav[second_string_attr][string_value][0][value]']);

    // String long
    $this->web_assert->elementTextContains('css', '.eav-list__item--string-long-attr .eav-list__attribute-label', EavAttribute::loadByMachineName('string_long_attr')->label());
    $this->web_assert->elementTextContains('css', '.eav-list__item--string-long-attr .eav-list__value', $form_values['field_eav[string_long_attr][string_long_value][0][value]']);

    // Integer
    $this->web_assert->elementTextContains('css', '.eav-list__item--integer-attr .eav-list__value', '11sffx');

    // Decimal
    $this->web_assert->elementTextContains('css', '.eav-list__item--decimal-attr .eav-list__value', '$12.60');

    // Boolean
    $this->web_assert->elementTextContains('css', '.eav-list__item--boolean-attr .eav-list__value', 'Yes');

    // Entity reference
    $this->web_assert->elementTextContains('css', '.eav-list__item--entity-reference-attr .eav-list__value', $this->categories['entity_reference_attr']->label());

    // List integer
    $this->web_assert->elementTextContains('css', '.eav-list__item--list-integer-attr .eav-list__value', 'Foo');

    // List string
    $this->web_assert->elementTextContains('css', '.eav-list__item--list-string-attr .eav-list__value', 'Foo');

    // Simple
    $this->web_assert->elementTextContains('css', '.eav-list__item--simple-attr .eav-list__attribute-label', EavAttribute::loadByMachineName('simple_attr')->label());
    $this->web_assert->elementTextContains('css', '.eav-list__item--simple-attr .eav-list__value', $form_values['field_eav[simple_attr][string_value][0][value]']);

    // Multi string
    $this->web_assert->elementTextContains('css', '.eav-list__item--multi-string-attr .eav-list__attribute-label', EavAttribute::loadByMachineName('multi_string_attr')->label());
    $this->web_assert->elementTextContains('css', '.eav-list__item--multi-string-attr .eav-list__value', $form_values['field_eav[multi_string_attr][string_value][0][value]']);

    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $node->delete();
  }

  private function _testEavFieldFormatterSort(): void {
    $node = $this->createProductNode($this->categories['all']->id());
    $this->drupalGetEavFormPage($node->id());
    $form_values = [
      'field_eav[string_attr][string_value][0][value]' => 'String value',
      'field_eav[second_string_attr][string_value][0][value]' => 'Second string value',
    ];
    $this->submitForm($form_values, 'Save');

    $this->drupalGet(Url::fromRoute('entity.node.canonical', ['node' => $node->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', '.eav-list__item--string-attr:nth-child(1)');
    $this->web_assert->elementExists('css', '.eav-list__item--second-string-attr:nth-child(2)');

    $second_string_attribute = EavAttribute::loadByMachineName('second_string_attr');
    $second_string_attribute_weight = $second_string_attribute->getWeight();
    $second_string_attribute->setWeight(-100);
    $second_string_attribute->save();
    drupal_flush_all_caches();

    $this->drupalGet(Url::fromRoute('entity.node.canonical', ['node' => $node->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', '.eav-list__item--second-string-attr:nth-child(1)');
    $this->web_assert->elementExists('css', '.eav-list__item--string-attr:nth-child(2)');

    // Clean
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $node->delete();

    $second_string_attribute->setWeight($second_string_attribute_weight);
    $second_string_attribute->save();
  }

  private function _testEavFieldFormatterWithLayoutBuilder(): void {
    // Install layout modules
    $module_installer = $this->container->get('module_installer');
    $module_installer->install(['layout_builder', 'layout_discovery']);

    // Turn on layout builder to product node bundle
    $this->drupalGet('admin/structure/types/manage/product/display');
    $this->dontSeeErrorMessage();
    $this->submitForm([
      'layout[enabled]' => TRUE,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'a#edit-manage-layout');

    // Crate node with attributes
    $node = $this->createProductNode($this->categories['all']->id());
    $this->drupalGetEavFormPage($node->id());
    $form_values = [
      'field_eav[string_attr][string_value][0][value]' => __FUNCTION__ . ' string',
    ];
    $this->submitForm($form_values, 'Save');

    // Test formatter
    $this->drupalGet(Url::fromRoute('entity.node.canonical', ['node' => $node->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'table.eav-list');

    // Clean environment
    $module_installer->uninstall(['layout_builder', 'layout_discovery']);
    $this->resetEntityStorageCaches();
    Node::load($node->id())->delete();
  }

  private function _testAttributeStorageSettingsFormAfterAddedEavValueEntities(): void {
    $string_attribute = EavAttribute::loadByMachineName('string_attr');
    $this->drupalGet(Url::fromRoute('entity.eav_attribute.value_storage_form', ['eav_attribute' => $string_attribute->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', '#edit-settings-max-length');
    $this->web_assert->elementNotExists('css', '#edit-settings-max-length[disabled]');
  }

  private function _testAttributesValuesFormSetEmptyValues(): void {
    $node = $this->createProductNode($this->categories['all']->id());
    $this->drupalGetEavFormPage($node->id());

    $this->submitForm([
      'field_eav[string_attr][string_value][0][value]' => '',
      'field_eav[second_string_attr][string_value][0][value]' => '',
      'field_eav[string_long_attr][string_long_value][0][value]' => '',
      'field_eav[integer_attr][integer_value][0][value]' => '',
      'field_eav[decimal_attr][decimal_value][0][value]' => '',
      'field_eav[boolean_attr][boolean_value][value]' => FALSE,
      'field_eav[entity_reference_attr][entity_reference_value]' => '_none',
      'field_eav[list_integer_attr][list_integer_value]' => '_none',
      'field_eav[list_string_attr][list_string_value]' => '_none',
      'field_eav[simple_attr][string_value][0][value]' => '',
      'field_eav[multi_string_attr][string_value][0][value]' => '',
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->seeSystemMessage('Values saved');

    $this->web_assert->fieldValueEquals('field_eav[string_attr][string_value][0][value]', '');
    $this->web_assert->fieldValueEquals('field_eav[second_string_attr][string_value][0][value]', '');
    $this->web_assert->fieldValueEquals('field_eav[string_long_attr][string_long_value][0][value]', '');
    $this->web_assert->fieldValueEquals('field_eav[integer_attr][integer_value][0][value]', '');
    $this->web_assert->fieldValueEquals('field_eav[decimal_attr][decimal_value][0][value]', '');
    $this->web_assert->fieldValueEquals('field_eav[entity_reference_attr][entity_reference_value]', '_none');
    $this->web_assert->fieldValueEquals('field_eav[list_integer_attr][list_integer_value]', '_none');
    $this->web_assert->fieldValueEquals('field_eav[list_string_attr][list_string_value]', '_none');
    $this->web_assert->fieldValueEquals('field_eav[simple_attr][string_value][0][value]', '');
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][0][value]', '');
    $this->web_assert->checkboxNotChecked('field_eav[boolean_attr][boolean_value][value]');

    $this->resetEntityStorageCaches();
    Node::load($node->id())->delete();
  }

  private function _testAttributesValuesFormClearButton(): void {
    $node = $this->createProductNode($this->categories['all']->id());
    $this->drupalGetEavFormPage($node->id());
    $this->submitForm([
      'field_eav[string_attr][string_value][0][value]' => __FUNCTION__,
      'field_eav[second_string_attr][string_value][0][value]' => __FUNCTION__,
      'field_eav[string_long_attr][string_long_value][0][value]' => __FUNCTION__,
      'field_eav[integer_attr][integer_value][0][value]' => '1',
      'field_eav[decimal_attr][decimal_value][0][value]' => '2',
      'field_eav[boolean_attr][boolean_value][value]' => TRUE,
      'field_eav[entity_reference_attr][entity_reference_value]' => $this->categories['entity_reference_attr']->id(),
      'field_eav[list_integer_attr][list_integer_value]' => '1',
      'field_eav[list_string_attr][list_string_value]' => 'baz',
      'field_eav[simple_attr][string_value][0][value]' => '', // Empty
      'field_eav[multi_string_attr][string_value][0][value]' => __FUNCTION__,
    ], 'Save');
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $this->assertEquals(10, $this->getEavFieldItems($node)->count());

    $this->click('#edit-delete');
    $this->dontSeeErrorMessage();
    $this->seeSystemMessage('Values cleared');

    $this->web_assert->fieldValueEquals('field_eav[string_attr][string_value][0][value]', EavAttribute::loadByMachineName('string_attr')->getValueFieldDefaultValues()[0]['value']);
    $this->web_assert->fieldValueEquals('field_eav[second_string_attr][string_value][0][value]', '');
    $this->web_assert->fieldValueEquals('field_eav[string_long_attr][string_long_value][0][value]', '');
    $this->web_assert->fieldValueEquals('field_eav[integer_attr][integer_value][0][value]', '');
    $this->web_assert->fieldValueEquals('field_eav[decimal_attr][decimal_value][0][value]', '');
    $this->web_assert->fieldValueEquals('field_eav[entity_reference_attr][entity_reference_value]', '_none');
    $this->web_assert->fieldValueEquals('field_eav[list_integer_attr][list_integer_value]', '_none');
    $this->web_assert->fieldValueEquals('field_eav[list_string_attr][list_string_value]', EavAttribute::loadByMachineName('list_string_attr')->getValueFieldDefaultValues()[0]['value']);
    $this->web_assert->fieldValueEquals('field_eav[simple_attr][string_value][0][value]', '');
    $this->web_assert->fieldValueEquals('field_eav[multi_string_attr][string_value][0][value]', '');
    $this->web_assert->checkboxNotChecked('field_eav[boolean_attr][boolean_value][value]');

    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $this->assertEquals(0, $this->getEavFieldItems($node)->count());
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value__string_value'));
    $this->assertEquals(0, $this->getDbTableRowsCount('eav_value__integer_value'));

    $node->delete();
  }

  private function _testGlobalAttribute(): void {
    $attribute = EavAttribute::create([
      'label' => 'Global attribute',
      'machine_name' => 'global_attr',
    ]);
    $attribute->save();

    $node = $this->createProductNode($this->categories['all']->id());
    $this->drupalGetEavFormPage($node->id());
    $this->web_assert->fieldExists('field_eav[global_attr][string_value][0][value]');
    $this->web_assert->fieldExists('field_eav[string_attr][string_value][0][value]');

    $form_values = [
      'field_eav[global_attr][string_value][0][value]' => 'Global attribute value ' . __FUNCTION__,
      'field_eav[string_attr][string_value][0][value]' => 'String attribute value ' . __FUNCTION__,
    ];
    $this->submitForm($form_values, 'Save');
    $this->dontSeeErrorMessage();
    foreach ($form_values as $field_name => $field_value) {
      $this->web_assert->fieldValueEquals($field_name, $field_value);
    }

    $this->resetEntityStorageCaches();
    Node::load($node->id())->delete();
  }

  private function _testHelperMethods(): void {
    $node = $this->createProductNode($this->categories['all']->id());
    $this->drupalGetEavFormPage($node->id());
    $this->submitForm([
      'field_eav[string_attr][string_value][0][value]' => __FUNCTION__,
    ], 'Save');
    $this->dontSeeErrorMessage();
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());

    $eav_field_items = $node->get('field_eav'); /** @var EavItemListInterface $eav_field_items */
    $this->assertInstanceOf(EavItemListInterface::class, $eav_field_items);

    $string_value_item = $eav_field_items->getItemByAttribute('string_attr');
    $this->assertInstanceOf(EavItemInterface::class, $string_value_item);

    $string_eav_value_entity = $string_value_item->getValueEntity();
    $this->assertInstanceOf(EavValueInterface::class, $string_eav_value_entity);

    $this->assertContains($string_eav_value_entity->id(), $eav_field_items->getValueEntitiesIds());

    $string_attribute = $string_eav_value_entity->getAttributeEntity();
    $this->assertInstanceOf(EavAttributeInterface::class, $string_attribute);

    $this->assertEquals((int)$string_attribute->id(), (int)$string_eav_value_entity->getAttributeId());
    $this->assertEquals('string_value', $string_attribute->getValueFieldName());
    $this->assertEquals('string_attr', $string_attribute->getMachineName());
    $this->assertEquals('string', $string_attribute->getValueType());
    $this->assertEquals('string_textfield', $string_attribute->getValueWidgetType());
    $this->assertEquals('string', $string_attribute->getValueFormatterType());
    $this->assertEquals(false, $string_attribute->isPrimary());
    $this->assertEquals([
      (int)$this->categories['string_attr']->id(),
      (int)$this->categories['string_and_multi_string_attr']->id(),
      (int)$this->categories['all']->id(),
    ], $string_attribute->getCategoriesIds());
    $this->assertInstanceOf(BundleFieldDefinition::class, $string_attribute->getValueFieldDefinition());

    $this->assertEquals('string_value', $string_eav_value_entity->getValueFieldName());
    $this->assertInstanceOf(FieldItemList::class, $string_eav_value_entity->getValueFieldItems());
    $this->assertEquals([0 => ['value' => __FUNCTION__]], $string_eav_value_entity->getValueFieldValues());

    $node->delete();
  }

  private function _testDeleteEavValueEntitiesAfterDeleteAttribute(): void {
    $node = $this->createProductNode($this->categories['all']->id());

    $attribute = EavAttribute::create([
      'label' => 'Attribute to delete',
      'machine_name' => 'attr_to_delete',
    ]);
    $attribute->save();

    $this->drupalGetEavFormPage($node->id());
    $this->web_assert->fieldExists('field_eav[attr_to_delete][string_value][0][value]');

    $this->submitForm([
      'field_eav[attr_to_delete][string_value][0][value]' => __FUNCTION__,
    ], 'Save');
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $eav_field_items = $this->getEavFieldItems($node);
    $eav_field_item = $eav_field_items->getItemByAttribute($attribute->getMachineName());
    $eav_value = $eav_field_item->getValueEntity();
    $eav_value_id = $eav_value->id();
    $eav_field_value = $eav_value->getValueFieldValues();
    $this->assertEquals(__FUNCTION__, $eav_field_value[0]['value']);
    $eav_values_ids = $eav_field_items->getValueEntitiesIds();

    $attribute->delete();
    $this->container->get('cron')->run();
    $this->resetEntityStorageCaches();
    $node = Node::load($node->id());
    $eav_field_items = $this->getEavFieldItems($node);
    $this->assertNull($eav_field_items->getItemByAttribute($attribute->getMachineName()));
    $this->assertNull(EavValue::load($eav_value_id));
    $this->assertCount(count($eav_values_ids) - 1, $eav_field_items->getValueEntitiesIds());

    $node->delete();
  }

  private function _testDeleteEavValueEntitiesAfterDeleteEavField(): void {
    // Setup
    $this->createEavField('node', 'page', 'field_page_eav', 'Page EAV');
    $page_node = $this->createNode([
      'type' => 'page',
      'title' => 'Page for ' . __FUNCTION__,
    ]);

    // Create eav_value entities
    $this->drupalGetEavFormPage($page_node->id(), 'node', 'field_page_eav');
    $this->submitForm([
      'field_page_eav[global_attr][string_value][0][value]' => __FUNCTION__,
    ], 'Save');
    $this->resetEntityStorageCaches();
    $page_node = Node::load($page_node->id());
    $eav_value_entities_ids = $this->getEavFieldItems($page_node, 'field_page_eav')->getValueEntitiesIds();
    $this->assertGreaterThan(0, count($eav_value_entities_ids));

    // Delete eav field
    $this->drupalGet('/admin/structure/types/manage/page/fields/node.page.field_page_eav/delete');
    $this->submitForm([], 'Delete');
    $this->web_assert->pageTextContains('has been deleted');
    $this->container->get('cron')->run();
    drupal_flush_all_caches();
    drupal_static_reset();
    $this->resetEntityStorageCaches();

    // Check result
    foreach ($eav_value_entities_ids as $eav_value_entity_id) {
      // @TODO Fix
      //$this->assertNull(EavValue::load($eav_value_entity_id));
    }

    $page_node->delete();
  }

  private function _testDeleteEavValueEntitiesAfterMoveAttributeFromCategory(): void {
    // @TODO
  }

  private function _testAttributesValuesFormAfterAddNewAttribute(): void {
    // @TODO
    // Set attributes values
    // Add new attribute
    // Test attributes form + form submit
  }

  private function _testAttributesValuesFormOnCommerceProduct(): void {
    // Install commerce_product module
    $module_installer = $this->container->get('module_installer');
    $module_installer->install(['commerce_product']);

    // Create store
    $store = Store::create([
      'type' => 'online',
      'name' => 'Default store',
    ]);
    $store->save();

    // Add field to default product type
    $this->createField(
      'commerce_product',
      'default',
      'field_eav',
      'eav',
      'EAV attributes',
      [],
      [],
      'eav_widget',
      [],
      'eav_formatter',
      []
    );
    drupal_flush_all_caches();

    // Create product
    $product = Product::create([
      'type' => 'default',
      'title' => 'Product 1',
    ]);
    $product->save();

    $this->drupalGet(Url::fromRoute('entity.commerce_product.canonical', ['commerce_product' => $product->id()]));
    $this->dontSeeErrorMessage();
    $this->web_assert->elementTextContains('css', '#block-local-tasks-block', 'Edit EAV attributes');

    $this->drupalGetEavFormPage($product->id(), 'commerce_product');
    $this->web_assert->elementExists('css', 'form.eav-entity-attributes-form');
  }

  private function _testLocalTaskVisibilityOnBundleWithoutEavField(): void {
    $product_node = $this->createProductNode($this->categories['all']->id());
    $this->drupalGetEntityPage($product_node);
    $this->dontSeeErrorMessage();
    $this->web_assert->elementExists('css', 'a[href="' . $this->getEntityEavFormUrl($product_node->id())->toString() . '"]');

    $page_node = $this->createNode([
      'type' => 'page',
      'title' => 'Page node for ' . __FUNCTION__,
    ]);
    $this->drupalGetEntityPage($page_node);
    $this->dontSeeErrorMessage();
    $this->web_assert->elementNotExists('css', 'a[href="' . $this->getEntityEavFormUrl($page_node->id(), 'node', 'field_page_eav')->toString() . '"]');
  }

  private function _testAttributesValuesFormAccessCheck(): void {
    // @TODO
  }

  private function _testTwoEavFieldsInOneEntityBundle(): void {
    // @TODO
  }

  private function _testDeleteEavValueEntitiesAfterUninstallModule(): void {
    // @TODO
  }

}

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

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