3 namespace Drupal\Tests\layout_builder\FunctionalJavascript;
5 use Drupal\block_content\Entity\BlockContentType;
6 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
7 use Drupal\Tests\contextual\FunctionalJavascript\ContextualLinkClickTrait;
10 * Base class for testing inline blocks.
12 abstract class InlineBlockTestBase extends WebDriverTestBase {
14 use ContextualLinkClickTrait;
17 * Locator for inline blocks.
19 const INLINE_BLOCK_LOCATOR = '.block-inline-blockbasic';
22 * Path prefix for the field UI for the test bundle.
24 const FIELD_UI_PREFIX = 'admin/structure/types/manage/bundle_with_section_field';
29 public static $modules = [
35 // @todo Remove after https://www.drupal.org/project/drupal/issues/2901792.
42 * @var \Drupal\Core\Entity\EntityStorageInterface
44 protected $blockStorage;
49 protected function setUp() {
51 // @todo The Layout Builder UI relies on local tasks; fix in
52 // https://www.drupal.org/project/drupal/issues/2917777.
53 $this->drupalPlaceBlock('local_tasks_block');
55 $this->createContentType(['type' => 'bundle_with_section_field', 'new_revision' => TRUE]);
57 'type' => 'bundle_with_section_field',
58 'title' => 'The node title',
61 'value' => 'The node body',
66 'type' => 'bundle_with_section_field',
67 'title' => 'The node2 title',
70 'value' => 'The node2 body',
74 $bundle = BlockContentType::create([
76 'label' => 'Basic block',
80 block_content_add_body_field($bundle->id());
82 $this->blockStorage = $this->container->get('entity_type.manager')->getStorage('block_content');
86 * Saves a layout and asserts the message is correct.
88 protected function assertSaveLayout() {
89 $assert_session = $this->assertSession();
90 $assert_session->linkExists('Save Layout');
91 // Go to the Save Layout page. Currently there are random test failures if
92 // 'clickLink()' is used.
93 // @todo Convert tests that extend this class to NightWatch tests in
94 // https://www.drupal.org/node/2984161
95 $link = $this->getSession()->getPage()->findLink('Save Layout');
96 $this->drupalGet($link->getAttribute('href'));
97 $this->assertNotEmpty($assert_session->waitForElement('css', '.messages--status'));
99 if (stristr($this->getUrl(), 'admin/structure') === FALSE) {
100 $assert_session->pageTextContains('The layout override has been saved.');
103 $assert_session->pageTextContains('The layout has been saved.');
108 * Gets the latest block entity id.
110 protected function getLatestBlockEntityId() {
111 $block_ids = \Drupal::entityQuery('block_content')->sort('id', 'DESC')->range(0, 1)->execute();
112 $block_id = array_pop($block_ids);
113 $this->assertNotEmpty($this->blockStorage->load($block_id));
118 * Removes an entity block from the layout but does not save the layout.
120 protected function removeInlineBlockFromLayout() {
121 $assert_session = $this->assertSession();
122 $page = $this->getSession()->getPage();
123 $block_text = $page->find('css', static::INLINE_BLOCK_LOCATOR)->getText();
124 $this->assertNotEmpty($block_text);
125 $assert_session->pageTextContains($block_text);
126 $this->clickContextualLink(static::INLINE_BLOCK_LOCATOR, 'Remove block');
127 $assert_session->waitForElement('css', "#drupal-off-canvas input[value='Remove']");
128 $assert_session->assertWaitOnAjaxRequest();
129 $page->find('css', '#drupal-off-canvas')->pressButton('Remove');
130 $this->waitForNoElement('#drupal-off-canvas');
131 $this->waitForNoElement(static::INLINE_BLOCK_LOCATOR);
132 $assert_session->assertWaitOnAjaxRequest();
133 $assert_session->pageTextNotContains($block_text);
137 * Adds an entity block to the layout.
139 * @param string $title
140 * The title field value.
141 * @param string $body
142 * The body field value.
144 protected function addInlineBlockToLayout($title, $body) {
145 $assert_session = $this->assertSession();
146 $page = $this->getSession()->getPage();
147 $page->clickLink('Add Block');
148 $assert_session->assertWaitOnAjaxRequest();
149 $this->assertNotEmpty($assert_session->waitForElementVisible('css', '.block-categories details:contains(Create new block)'));
150 $this->clickLink('Basic block');
151 $assert_session->assertWaitOnAjaxRequest();
152 $textarea = $assert_session->waitForElement('css', '[name="settings[block_form][body][0][value]"]');
153 $this->assertNotEmpty($textarea);
154 $assert_session->fieldValueEquals('Title', '');
155 $page->findField('Title')->setValue($title);
156 $textarea->setValue($body);
157 $page->pressButton('Add Block');
158 $this->assertDialogClosedAndTextVisible($body, static::INLINE_BLOCK_LOCATOR);
162 * Configures an inline block in the Layout Builder.
164 * @param string $old_body
165 * The old body field value.
166 * @param string $new_body
167 * The new body field value.
168 * @param string $block_css_locator
169 * The CSS locator to use to select the contextual link.
171 protected function configureInlineBlock($old_body, $new_body, $block_css_locator = NULL) {
172 $block_css_locator = $block_css_locator ?: static::INLINE_BLOCK_LOCATOR;
173 $assert_session = $this->assertSession();
174 $page = $this->getSession()->getPage();
175 $this->clickContextualLink($block_css_locator, 'Configure');
176 $textarea = $assert_session->waitForElementVisible('css', '[name="settings[block_form][body][0][value]"]');
177 $this->assertNotEmpty($textarea);
178 $this->assertSame($old_body, $textarea->getValue());
179 $textarea->setValue($new_body);
180 $page->pressButton('Update');
181 $this->waitForNoElement('#drupal-off-canvas');
182 $assert_session->assertWaitOnAjaxRequest();
183 $this->assertDialogClosedAndTextVisible($new_body);
187 * Waits for an element to be removed from the page.
189 * @param string $selector
191 * @param int $timeout
192 * (optional) Timeout in milliseconds, defaults to 10000.
194 * @todo Remove in https://www.drupal.org/node/2892440.
196 protected function waitForNoElement($selector, $timeout = 10000) {
197 $condition = "(typeof jQuery !== 'undefined' && jQuery('$selector').length === 0)";
198 $this->assertJsCondition($condition, $timeout);
202 * Asserts that the dialog closes and the new text appears on the main canvas.
204 * @param string $text
206 * @param string|null $css_locator
207 * The css locator to use inside the main canvas if any.
209 protected function assertDialogClosedAndTextVisible($text, $css_locator = NULL) {
210 $assert_session = $this->assertSession();
211 $this->waitForNoElement('#drupal-off-canvas');
212 $assert_session->assertWaitOnAjaxRequest();
213 $assert_session->elementNotExists('css', '#drupal-off-canvas');
215 $this->assertNotEmpty($assert_session->waitForElementVisible('css', ".dialog-off-canvas-main-canvas $css_locator:contains('$text')"));
218 $this->assertNotEmpty($assert_session->waitForElementVisible('css', ".dialog-off-canvas-main-canvas:contains('$text')"));