Pull merge.
[yaffs-website] / web / core / modules / layout_builder / tests / src / FunctionalJavascript / InlineBlockTestBase.php
1 <?php
2
3 namespace Drupal\Tests\layout_builder\FunctionalJavascript;
4
5 use Drupal\block_content\Entity\BlockContentType;
6 use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
7 use Drupal\Tests\contextual\FunctionalJavascript\ContextualLinkClickTrait;
8
9 /**
10  * Base class for testing inline blocks.
11  */
12 abstract class InlineBlockTestBase extends WebDriverTestBase {
13
14   use ContextualLinkClickTrait;
15
16   /**
17    * Locator for inline blocks.
18    */
19   const INLINE_BLOCK_LOCATOR = '.block-inline-blockbasic';
20
21   /**
22    * Path prefix for the field UI for the test bundle.
23    */
24   const FIELD_UI_PREFIX = 'admin/structure/types/manage/bundle_with_section_field';
25
26   /**
27    * {@inheritdoc}
28    */
29   public static $modules = [
30     'block_content',
31     'layout_builder',
32     'block',
33     'node',
34     'contextual',
35     // @todo Remove after https://www.drupal.org/project/drupal/issues/2901792.
36     'no_transitions_css',
37   ];
38
39   /**
40    * The block storage.
41    *
42    * @var \Drupal\Core\Entity\EntityStorageInterface
43    */
44   protected $blockStorage;
45
46   /**
47    * {@inheritdoc}
48    */
49   protected function setUp() {
50     parent::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');
54
55     $this->createContentType(['type' => 'bundle_with_section_field', 'new_revision' => TRUE]);
56     $this->createNode([
57       'type' => 'bundle_with_section_field',
58       'title' => 'The node title',
59       'body' => [
60         [
61           'value' => 'The node body',
62         ],
63       ],
64     ]);
65     $this->createNode([
66       'type' => 'bundle_with_section_field',
67       'title' => 'The node2 title',
68       'body' => [
69         [
70           'value' => 'The node2 body',
71         ],
72       ],
73     ]);
74     $this->createBlockContentType('basic', 'Basic block');
75
76     $this->blockStorage = $this->container->get('entity_type.manager')->getStorage('block_content');
77   }
78
79   /**
80    * Saves a layout and asserts the message is correct.
81    */
82   protected function assertSaveLayout() {
83     $assert_session = $this->assertSession();
84     $assert_session->linkExists('Save Layout');
85     // Go to the Save Layout page. Currently there are random test failures if
86     // 'clickLink()' is used.
87     // @todo Convert tests that extend this class to NightWatch tests in
88     // https://www.drupal.org/node/2984161
89     $link = $this->getSession()->getPage()->findLink('Save Layout');
90     $this->drupalGet($link->getAttribute('href'));
91     $this->assertNotEmpty($assert_session->waitForElement('css', '.messages--status'));
92
93     if (stristr($this->getUrl(), 'admin/structure') === FALSE) {
94       $assert_session->pageTextContains('The layout override has been saved.');
95     }
96     else {
97       $assert_session->pageTextContains('The layout has been saved.');
98     }
99   }
100
101   /**
102    * Gets the latest block entity id.
103    */
104   protected function getLatestBlockEntityId() {
105     $block_ids = \Drupal::entityQuery('block_content')->sort('id', 'DESC')->range(0, 1)->execute();
106     $block_id = array_pop($block_ids);
107     $this->assertNotEmpty($this->blockStorage->load($block_id));
108     return $block_id;
109   }
110
111   /**
112    * Removes an entity block from the layout but does not save the layout.
113    */
114   protected function removeInlineBlockFromLayout() {
115     $assert_session = $this->assertSession();
116     $page = $this->getSession()->getPage();
117     $block_text = $page->find('css', static::INLINE_BLOCK_LOCATOR)->getText();
118     $this->assertNotEmpty($block_text);
119     $assert_session->pageTextContains($block_text);
120     $this->clickContextualLink(static::INLINE_BLOCK_LOCATOR, 'Remove block');
121     $assert_session->waitForElement('css', "#drupal-off-canvas input[value='Remove']");
122     $assert_session->assertWaitOnAjaxRequest();
123     $page->find('css', '#drupal-off-canvas')->pressButton('Remove');
124     $this->waitForNoElement('#drupal-off-canvas');
125     $this->waitForNoElement(static::INLINE_BLOCK_LOCATOR);
126     $assert_session->assertWaitOnAjaxRequest();
127     $assert_session->pageTextNotContains($block_text);
128   }
129
130   /**
131    * Adds an entity block to the layout.
132    *
133    * @param string $title
134    *   The title field value.
135    * @param string $body
136    *   The body field value.
137    */
138   protected function addInlineBlockToLayout($title, $body) {
139     $assert_session = $this->assertSession();
140     $page = $this->getSession()->getPage();
141     $page->clickLink('Add Block');
142     $assert_session->assertWaitOnAjaxRequest();
143     $this->assertNotEmpty($assert_session->waitForLink('Create custom block'));
144     $this->clickLink('Create custom block');
145     $assert_session->assertWaitOnAjaxRequest();
146     $textarea = $assert_session->waitForElement('css', '[name="settings[block_form][body][0][value]"]');
147     $this->assertNotEmpty($textarea);
148     $assert_session->fieldValueEquals('Title', '');
149     $page->findField('Title')->setValue($title);
150     $textarea->setValue($body);
151     $page->pressButton('Add Block');
152     $this->assertDialogClosedAndTextVisible($body, static::INLINE_BLOCK_LOCATOR);
153   }
154
155   /**
156    * Configures an inline block in the Layout Builder.
157    *
158    * @param string $old_body
159    *   The old body field value.
160    * @param string $new_body
161    *   The new body field value.
162    * @param string $block_css_locator
163    *   The CSS locator to use to select the contextual link.
164    */
165   protected function configureInlineBlock($old_body, $new_body, $block_css_locator = NULL) {
166     $block_css_locator = $block_css_locator ?: static::INLINE_BLOCK_LOCATOR;
167     $assert_session = $this->assertSession();
168     $page = $this->getSession()->getPage();
169     $this->clickContextualLink($block_css_locator, 'Configure');
170     $textarea = $assert_session->waitForElementVisible('css', '[name="settings[block_form][body][0][value]"]');
171     $this->assertNotEmpty($textarea);
172     $this->assertSame($old_body, $textarea->getValue());
173     $textarea->setValue($new_body);
174     $page->pressButton('Update');
175     $this->waitForNoElement('#drupal-off-canvas');
176     $assert_session->assertWaitOnAjaxRequest();
177     $this->assertDialogClosedAndTextVisible($new_body);
178   }
179
180   /**
181    * Waits for an element to be removed from the page.
182    *
183    * @param string $selector
184    *   CSS selector.
185    * @param int $timeout
186    *   (optional) Timeout in milliseconds, defaults to 10000.
187    *
188    * @todo Remove in https://www.drupal.org/node/2892440.
189    */
190   protected function waitForNoElement($selector, $timeout = 10000) {
191     $condition = "(typeof jQuery !== 'undefined' && jQuery('$selector').length === 0)";
192     $this->assertJsCondition($condition, $timeout);
193   }
194
195   /**
196    * Asserts that the dialog closes and the new text appears on the main canvas.
197    *
198    * @param string $text
199    *   The text.
200    * @param string|null $css_locator
201    *   The css locator to use inside the main canvas if any.
202    */
203   protected function assertDialogClosedAndTextVisible($text, $css_locator = NULL) {
204     $assert_session = $this->assertSession();
205     $this->waitForNoElement('#drupal-off-canvas');
206     $assert_session->assertWaitOnAjaxRequest();
207     $assert_session->elementNotExists('css', '#drupal-off-canvas');
208     if ($css_locator) {
209       $this->assertNotEmpty($assert_session->waitForElementVisible('css', ".dialog-off-canvas-main-canvas $css_locator:contains('$text')"));
210     }
211     else {
212       $this->assertNotEmpty($assert_session->waitForElementVisible('css', ".dialog-off-canvas-main-canvas:contains('$text')"));
213     }
214   }
215
216   /**
217    * Creates a block content type.
218    *
219    * @param string $id
220    *   The block type id.
221    * @param string $label
222    *   The block type label.
223    */
224   protected function createBlockContentType($id, $label) {
225     $bundle = BlockContentType::create([
226       'id' => $id,
227       'label' => $label,
228       'revision' => 1,
229     ]);
230     $bundle->save();
231     block_content_add_body_field($bundle->id());
232   }
233
234 }