Skip to content
Snippets Groups Projects
Commit aaf9928f authored by christian.wiedemann's avatar christian.wiedemann Committed by Mikael Meulle
Browse files

Issue #3470386 by christian.wiedemann: Functional Tests Framework

parent 90656879
No related branches found
No related tags found
1 merge request!192Resolve #3470386 "2.0.0 beta2 render"
Pipeline #278580 passed with warnings
Showing
with 537 additions and 40 deletions
<?php
namespace Drupal\Tests\ui_patterns_layouts\Functional;
use Drupal\Tests\ui_patterns\Functional\UiPatternsFunctionalTestBase;
use Drupal\Tests\ui_patterns\Traits\TestDataTrait;
/**
* Test pattern preview rendering.
*
* @group ui_patterns_layouts
*/
class LayoutBuilderFieldFormatterRenderTest extends UiPatternsFunctionalTestBase {
use TestDataTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'node',
'ui_patterns',
'ui_patterns_test',
'ui_patterns_layouts',
'ui_patterns_field_formatters',
'field_ui',
'layout_builder',
'block',
];
/**
* Test the form and the existence of the.
*/
public function testContextInForm(): void {
$this->createTestContentContentType();
$assert_session = $this->assertSession();
$config_import = $this->loadConfigFixture(__DIR__ . '/../fixtures/core.entity_view_display.node.page.full.yml');
$ui_patterns_config = &$config_import['third_party_settings']['layout_builder']['sections'][0]['components']['6d778a84-cdc2-4a00-af66-54dab3ea2bf7']['configuration']['formatter']['settings']['ui_patterns'];
$test_data = $this->loadTestDataFixture();
$test_set = $test_data->getTestSet('context_exists_default');
$ui_patterns_config = $this->buildUiPatternsConfig($test_set);
$this->importConfigFixture(
'core.entity_view_display.node.page.full',
$config_import
);
$this->drupalGet('layout_builder/update/block/defaults/node.page.full/0/wrapper/6d778a84-cdc2-4a00-af66-54dab3ea2bf7');
$assert_session->elementTextEquals('css', '.context-exists', $test_set['output']['props']['string']['value']);
}
/**
* Tests preview and output of props.
*/
public function testRender(): void {
$assert_session = $this->assertSession();
$config_import = $this->loadConfigFixture(__DIR__ . '/../fixtures/core.entity_view_display.node.page.full.yml');
$ui_patterns_config = &$config_import['third_party_settings']['layout_builder']['sections'][0]['components']['6d778a84-cdc2-4a00-af66-54dab3ea2bf7']['configuration']['formatter']['settings']['ui_patterns'];
$test_data = $this->loadTestDataFixture();
$tests = [
$test_data->getTestSet('textfield_default'),
];
foreach ($tests as $test_set) {
$node = $this->createTestContentNode('page', $test_set['entity'] ?? []);
$ui_patterns_config = $this->buildUiPatternsConfig($test_set);
$this->importConfigFixture(
'core.entity_view_display.node.page.full',
$config_import
);
$this->drupalGet('node/' . $node->id());
$assert_session->elementExists('css', '#ui-patterns-wrapper-wrapper');
$assert_session->elementExists('css', '#ui-patterns-test-component');
$this->validateRenderedComponent($test_set);
}
}
}
langcode: en
status: true
third_party_settings:
layout_builder:
enabled: true
allow_custom: false
sections:
-
layout_id: 'ui_patterns:ui_patterns_test:test_wrapper_component'
layout_settings:
label: ''
context_mapping: { }
ui_patterns:
component_id: null
variant_id: null
slots: { }
props: { }
components:
6d778a84-cdc2-4a00-af66-54dab3ea2bf7:
uuid: 6d778a84-cdc2-4a00-af66-54dab3ea2bf7
region: wrapper
configuration:
id: 'field_block:node:page:body'
label: Body
label_display: '0'
provider: layout_builder
context_mapping:
entity: layout_builder.entity
view_mode: view_mode
formatter:
type: ui_patterns_component_per_item
label: hidden
settings:
ui_patterns:
component_id: 'ui_patterns_test:test-component'
variant_id: null
slots: { }
props: { }
third_party_settings: { }
weight: 0
additional: { }
third_party_settings: { }
entity_test:
foo: bar
id: node.page.full
targetEntityType: node
bundle: page
mode: full
content: {}
hidden:
layout_builder__layout: true
<?php
namespace Drupal\Tests\ui_patterns_layouts\Functional;
use Drupal\Tests\ui_patterns\Functional\UiPatternsFunctionalTestBase;
use Drupal\Tests\ui_patterns\Traits\TestDataTrait;
/**
* Test pattern preview rendering.
*
* @group ui_patterns_layouts
*/
class LayoutBuilderRenderTest extends UiPatternsFunctionalTestBase {
use TestDataTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'node',
'ui_patterns',
'ui_patterns_test',
'ui_patterns_layouts',
'field_ui',
'layout_builder',
'block',
];
/**
* Test the form and the existence of the.
*/
public function testContextInForm(): void {
$assert_session = $this->assertSession();
$config_import = $this->loadConfigFixture(__DIR__ . '/../fixtures/core.entity_view_display.node.page.full.yml');
$ui_patterns_config = &$config_import['third_party_settings']['layout_builder']['sections'][0]['layout_settings']['ui_patterns'];
$test_data = $this->loadTestDataFixture();
$test_set = $test_data->getTestSet('context_exists_default');
$this->createTestContentContentType();
$ui_patterns_config = $this->buildUiPatternsConfig($test_set);
$this->importConfigFixture(
'core.entity_view_display.node.page.full',
$config_import
);
$this->drupalGet('admin/structure/types/manage/page/display/full/layout');
$this->click('.layout-builder__link--configure');
$assert_session->elementTextEquals('css', '.context-exists', $test_set['output']['props']['string']['value']);
}
/**
* Tests preview and output of props.
*/
public function testRenderProps(): void {
$assert_session = $this->assertSession();
$config_import = $this->loadConfigFixture(__DIR__ . '/../fixtures/core.entity_view_display.node.page.full.yml');
$ui_patterns_config = &$config_import['third_party_settings']['layout_builder']['sections'][0]['layout_settings']['ui_patterns'];
$test_data = $this->loadTestDataFixture();
$tests = [
$test_data->getTestSet('textfield_default'),
$test_data->getTestSet('token_default'),
$test_data->getTestSet('context_exists_default'),
];
foreach ($tests as $test_set) {
$node = $this->createTestContentNode('page', $test_set['entity'] ?? []);
$ui_patterns_config = $this->buildUiPatternsConfig($test_set);
$this->importConfigFixture(
'core.entity_view_display.node.page.full',
$config_import
);
$this->drupalGet('admin/structure/types/manage/page/display/full/layout');
$assert_session->elementExists('css', '#ui-patterns-test-component');
$this->drupalGet('node/' . $node->id());
$assert_session->elementExists('css', '#ui-patterns-test-component');
$this->validateRenderedComponent($test_set);
}
}
/**
* Tests preview and output of slots.
*/
public function testRenderSlots(): void {
$node = $this->createTestContentNode('page', ['field_text_1' => 'field_text_1 value']);
$config_import = $this->loadConfigFixture(__DIR__ . '/../fixtures/core.entity_view_display.node.page.full.yml');
$this->importConfigFixture(
'core.entity_view_display.node.page.full',
$config_import
);
$assert_session = $this->assertSession();
$page = $this->getSession()->getPage();
$this->drupalGet('admin/structure/types/manage/page/display/full/layout');
$assert_session->elementExists('css', '#ui-patterns-test-component');
// Add body to slot and check for existence.
$page->clickLink('Add block');
$page->clickLink('Text (formatted)');
$page->pressButton('Add block');
$page->pressButton('Save layout');
$this->drupalGet('node/' . $node->id());
$assert_session->elementExists('css', '#ui-patterns-test-component');
$assert_session->elementTextContains('css', '#ui-patterns-slots-slot', 'field_text_1 value');
}
}
......@@ -17,7 +17,6 @@ use Symfony\Component\Yaml\Yaml;
*/
abstract class UIPatternsLayoutsTestBase extends EntityTestBase {
/**
* Additional modules to activate (child classes should set this).
*
......
langcode: en
status: true
third_party_settings:
layout_builder:
enabled: true
allow_custom: false
sections:
-
layout_id: 'ui_patterns:ui_patterns_test:test_component'
layout_settings:
label: TestDemo
context_mapping: { }
ui_patterns:
component_id: null
variant_id: null
slots: { }
props: { }
components: { }
third_party_settings: { }
id: node.page.full
targetEntityType: node
bundle: page
mode: full
hidden:
layout_builder__layout: true
name: "UI Patterns Test wrapper component"
props:
type: object
properties: {}
slots:
wrapper:
title: "Wrapper"
description: "Wrapper"
<div id="ui-patterns-wrapper">
<div id="ui-patterns-wrapper-wrapper">
{{ wrapper }}
</div>
</div>
<?php
declare(strict_types=1);
namespace Drupal\ui_patterns_test\Plugin\UiPatterns\Source;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\ui_patterns\Attribute\Source;
use Drupal\ui_patterns\SourcePluginBase;
/**
* Plugin implementation of the source_provider.
*/
#[Source(
id: 'context_exists',
label: new TranslatableMarkup('Context exists'),
description: new TranslatableMarkup('Test Plugin to display context.'),
prop_types: ['string'],
context_definitions: [
'entity' => new ContextDefinition('entity', label: new TranslatableMarkup('Entity'), required: FALSE),
]
)]
final class ContextExists extends SourcePluginBase {
/**
* {@inheritdoc}
*/
public function defaultConfiguration(): array {
return ['context_type' => 'entity'];
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state): array {
$form['context_exists'] = [
'#type' => 'markup',
'#markup' => '<div class="context-exists">' . $this->getPropValue() . '</div>',
];
$form['context_type'] = [
'#type' => 'select',
'#options' => [
'entity' => 'Entity',
],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function getPropValue(): mixed {
$context_type = $this->getSetting('context_type') ?? 'entity';
$entity = $this->getContextValue($context_type);
return $context_type . ' exists: ' . ($entity !== NULL);
}
}
<?php
declare(strict_types=1);
namespace Drupal\Tests\ui_patterns\Functional;
use Drupal\Component\Serialization\Yaml;
use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\ui_patterns\Traits\TestContentCreationTrait;
use Drupal\Tests\ui_patterns\Traits\TestDataTrait;
/**
* Base function testing.
*
* @group ui_patterns
*/
abstract class UiPatternsFunctionalTestBase extends BrowserTestBase {
use TestContentCreationTrait;
use TestDataTrait;
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'ui_patterns_test_theme';
/**
* {@inheritdoc}
*/
protected static $modules = [
'node',
'ui_patterns',
'ui_patterns_layouts',
'field_ui',
];
/**
* Config is initialized.
*/
private bool $configInitialize = FALSE;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$user = $this->drupalCreateUser([
'configure any layout',
'administer node display',
], NULL, TRUE);
if ($user) {
$this->drupalLogin($user);
}
}
/**
* Initialize config.
*/
private function initializeConfig() {
if ($this->configInitialize === FALSE) {
$this->copyConfig(\Drupal::service('config.storage'), \Drupal::service('config.storage.sync'));
}
$this->configInitialize = TRUE;
}
/**
* Load a configure fixture.
*
* @param string $path
* The path to the fixture.
*
* @return array
* The fixture.
*/
public function loadConfigFixture(string $path):array {
$yaml = file_get_contents($path);
if ($yaml === FALSE) {
throw new \InvalidArgumentException($path . ' not found.');
}
return Yaml::decode($yaml);
}
/**
* Import config fixture.
*
* @param string $config_id
* The config id.
* @param array $config
* The config fixture.
*/
public function importConfigFixture(string $config_id, array $config) {
$this->initializeConfig();
\Drupal::service('config.storage.sync')->write($config_id, $config);
$config_importer = $this->configImporter();
$config_importer->import();
}
/**
* Build UI Patterns compatible configuration for given test_set.
*
* @param array $test_set
* The test_set to build the configuration from.
*
* @return array
* The builded configuration.
*/
protected function buildUiPatternsConfig(array $test_set):array {
if (!isset($test_set['component']['slots'])) {
$test_set['component']['slots'] = [];
}
return $test_set['component'];
}
/**
* Validates rendered component.
*
* @param array $test_set
* The test set to validate against.
*
* @throws \Behat\Mink\Exception\ElementNotFoundException
*/
protected function validateRenderedComponent($test_set) {
$output = $test_set['output'] ?? [];
foreach ($output as $prop_or_slot => $prop_or_slot_item) {
foreach ($prop_or_slot_item as $prop_name => $output) {
$type = $prop_or_slot;
$assert_session = $this->assertSession();
$selector = '#ui-patterns-' . $type . '-' . $prop_name;
$element = $assert_session->elementExists('css', $selector);
$prop_value = $element->getText();
$message = sprintf("Test '%s' failed for prop/slot '%s' of component %s. Selector %s", $test_set["name"] ?? "", $prop_or_slot, $test_set['component']['component_id'], $selector);
$this->assertExpectedOutput($output, $prop_value, $message);
}
}
}
}
......@@ -43,7 +43,8 @@ class SourcePluginsTestBase extends KernelTestBase {
parent::setUp();
$this->installEntitySchema('node');
$this->installEntitySchema('user');
$this->createContentType();
$this->installConfig(['system', 'filter']);
$this->createTestContentContentType();
}
/**
......@@ -52,7 +53,7 @@ class SourcePluginsTestBase extends KernelTestBase {
protected function getSourceContexts(array $test_set = []): array {
$context = [];
if (isset($test_set['entity'])) {
$entity = $this->createNode('page', is_array($test_set['entity']) ? $test_set['entity'] : []);
$entity = $this->createTestContentNode('page', is_array($test_set['entity']) ? $test_set['entity'] : []);
$context['entity'] = EntityContext::fromEntity($entity);
}
return $context;
......
......@@ -15,6 +15,8 @@ use function PHPUnit\Framework\assertTrue;
*/
trait RunSourcePluginTestTrait {
use TestDataTrait;
/**
* Return the component manager.
*/
......@@ -59,30 +61,6 @@ trait RunSourcePluginTestTrait {
return array_merge($contexts, $this->getSourceContexts($test_set));
}
/**
* Assert an expected output.
*
* @param array $expected_result
* The expected result.
* @param string $result
* The result.
* @param string $message
* The message.
*
* @throws \RuntimeException
*/
private function assertExpectedOutput(array $expected_result, mixed $result, string $message = ''): void {
if (isset($expected_result['value'])) {
$this->assertEquals($expected_result['value'], $result, $message);
}
elseif (isset($expected_result['regEx'])) {
$this->assertTrue(preg_match($expected_result['regEx'], $result) === 1, $message);
}
else {
throw new \RuntimeException(sprintf('Missing "value" or "regEx" in expected result %s', print_r($expected_result, TRUE)));
}
}
/**
* Get the type definition of a prop or slot.
*
......
......@@ -37,10 +37,9 @@ trait TestContentCreationTrait {
* @param array $values
* Values applied to create method of the node.
*/
private function createNode(string $bundle = 'page', array $values = []): NodeInterface {
$this->createContentType($bundle);
protected function createTestContentNode(string $bundle = 'page', array $values = []): NodeInterface {
$this->createTestContentContentType($bundle);
$node = $this->drupalCreateNode(['type' => $bundle] + $values);
$this->drupalCreateNode();
return $node;
}
......@@ -51,7 +50,7 @@ trait TestContentCreationTrait {
* - field_"type" with cardinality -1
* - field_"type"_1 with cardinality 1
*/
protected function createContentType($bundle = 'page'): NodeType {
protected function createTestContentContentType($bundle = 'page'): NodeType {
if ($type = NodeType::load($bundle)) {
return $type;
}
......@@ -61,6 +60,9 @@ trait TestContentCreationTrait {
'type' => $bundle,
]);
$type->save();
$this->createEntityField($type->getEntityType()->getBundleOf(), $bundle, 'body', 'text_long', 1);
$field_types = $this->getFieldTypePluginManager()->getDefinitions();
foreach (array_keys($field_types) as $field_type_id) {
......@@ -89,14 +91,21 @@ trait TestContentCreationTrait {
) : FieldConfigInterface {
$field_type_definition = $this->getFieldTypePluginManager()->getDefinition($field_type_id);
// Create a field storage.
$field_storage = [
'field_name' => $field_name,
'entity_type' => $entity_type,
'type' => $field_type_id,
'settings' => [],
'cardinality' => $cardinality,
];
FieldStorageConfig::create($field_storage)->save();
$existing_field_storage = FieldStorageConfig::loadByName($entity_type, $field_name);
if ($existing_field_storage === NULL) {
$field_storage = [
'field_name' => $field_name,
'entity_type' => $entity_type,
'type' => $field_type_id,
'settings' => [],
'cardinality' => $cardinality,
];
FieldStorageConfig::create($field_storage)->save();
}
else {
$field_storage = $existing_field_storage->toArray();
}
// Create a field instance on the content type.
$field = [
'field_name' => $field_storage['field_name'],
......
......@@ -11,10 +11,34 @@ use Drupal\Component\Serialization\Yaml;
*/
trait TestDataTrait {
/**
* Assert an expected output with the configuration from the test set.
*
* @param array $expected_result
* The expected result from the test set.
* @param string $result
* The result.
* @param string $message
* The message.
*
* @throws \RuntimeException
*/
protected function assertExpectedOutput(array $expected_result, mixed $result, string $message = ''): void {
if (isset($expected_result['value'])) {
$this->assertContains($expected_result['value'], [$result], $message);
}
elseif (isset($expected_result['regEx'])) {
$this->assertTrue(preg_match($expected_result['regEx'], $result) === 1, $message);
}
else {
throw new \RuntimeException(sprintf('Missing "value" or "regEx" in expected result %s', print_r($expected_result, TRUE)));
}
}
/**
* Loads test dataset fixture.
*/
protected static function loadTestDataFixture($path) {
protected static function loadTestDataFixture($path = __DIR__ . "/../fixtures/TestDataSet.yml") {
return new class($path) {
/**
......
......@@ -56,3 +56,14 @@ field_property_default:
slot:
-
value: "value_text_1"
context_exists_default:
component:
component_id: ui_patterns_test:test-component
props:
string:
source_id: context_exists
output:
props:
string:
value: 'entity exists: 1'
entity: {}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment