Pull merge.
[yaffs-website] / web / core / modules / layout_builder / tests / src / Functional / LayoutBuilderTest.php
1 <?php
2
3 namespace Drupal\Tests\layout_builder\Functional;
4
5 use Drupal\node\Entity\Node;
6 use Drupal\Tests\BrowserTestBase;
7 use Drupal\views\Entity\View;
8
9 /**
10  * Tests the Layout Builder UI.
11  *
12  * @group layout_builder
13  */
14 class LayoutBuilderTest extends BrowserTestBase {
15
16   /**
17    * {@inheritdoc}
18    */
19   public static $modules = [
20     'views',
21     'layout_builder',
22     'layout_builder_views_test',
23     'layout_test',
24     'block',
25     'block_test',
26     'node',
27     'layout_builder_test',
28   ];
29
30   /**
31    * {@inheritdoc}
32    */
33   protected function setUp() {
34     parent::setUp();
35
36     // @todo The Layout Builder UI relies on local tasks; fix in
37     //   https://www.drupal.org/project/drupal/issues/2917777.
38     $this->drupalPlaceBlock('local_tasks_block');
39
40     // Create two nodes.
41     $this->createContentType(['type' => 'bundle_with_section_field']);
42     $this->createNode([
43       'type' => 'bundle_with_section_field',
44       'title' => 'The first node title',
45       'body' => [
46         [
47           'value' => 'The first node body',
48         ],
49       ],
50     ]);
51     $this->createNode([
52       'type' => 'bundle_with_section_field',
53       'title' => 'The second node title',
54       'body' => [
55         [
56           'value' => 'The second node body',
57         ],
58       ],
59     ]);
60   }
61
62   /**
63    * {@inheritdoc}
64    */
65   public function testLayoutBuilderUi() {
66     $assert_session = $this->assertSession();
67     $page = $this->getSession()->getPage();
68
69     $this->drupalLogin($this->drupalCreateUser([
70       'configure any layout',
71       'administer node display',
72       'administer node fields',
73     ]));
74
75     $this->drupalGet('node/1');
76     $assert_session->pageTextContains('The first node body');
77     $assert_session->pageTextNotContains('Powered by Drupal');
78     $assert_session->linkNotExists('Layout');
79
80     $field_ui_prefix = 'admin/structure/types/manage/bundle_with_section_field';
81
82     // From the manage display page, go to manage the layout.
83     $this->drupalGet("$field_ui_prefix/display/default");
84     $assert_session->linkNotExists('Manage layout');
85     $assert_session->fieldDisabled('layout[allow_custom]');
86
87     $this->drupalPostForm(NULL, ['layout[enabled]' => TRUE], 'Save');
88     $assert_session->linkExists('Manage layout');
89     $this->clickLink('Manage layout');
90     $assert_session->addressEquals("$field_ui_prefix/display-layout/default");
91     // The body field is only present once.
92     $assert_session->elementsCount('css', '.field--name-body', 1);
93     // The extra field is only present once.
94     $assert_session->pageTextContainsOnce('Placeholder for the "Extra label" field');
95     // Save the defaults.
96     $assert_session->linkExists('Save Layout');
97     $this->clickLink('Save Layout');
98     $assert_session->addressEquals("$field_ui_prefix/display/default");
99
100     // Load the default layouts again after saving to confirm fields are only
101     // added on new layouts.
102     $this->drupalGet("$field_ui_prefix/display/default");
103     $assert_session->linkExists('Manage layout');
104     $this->clickLink('Manage layout');
105     $assert_session->addressEquals("$field_ui_prefix/display-layout/default");
106     // The body field is only present once.
107     $assert_session->elementsCount('css', '.field--name-body', 1);
108     // The extra field is only present once.
109     $assert_session->pageTextContainsOnce('Placeholder for the "Extra label" field');
110
111     // Add a new block.
112     $assert_session->linkExists('Add Block');
113     $this->clickLink('Add Block');
114     $assert_session->linkExists('Powered by Drupal');
115     $this->clickLink('Powered by Drupal');
116     $page->fillField('settings[label]', 'This is the label');
117     $page->checkField('settings[label_display]');
118     $page->pressButton('Add Block');
119     $assert_session->pageTextContains('Powered by Drupal');
120     $assert_session->pageTextContains('This is the label');
121     $assert_session->addressEquals("$field_ui_prefix/display-layout/default");
122
123     // Save the defaults.
124     $assert_session->linkExists('Save Layout');
125     $this->clickLink('Save Layout');
126     $assert_session->pageTextContains('The layout has been saved.');
127     $assert_session->addressEquals("$field_ui_prefix/display/default");
128
129     // The node uses the defaults, no overrides available.
130     $this->drupalGet('node/1');
131     $assert_session->pageTextContains('The first node body');
132     $assert_session->pageTextContains('Powered by Drupal');
133     $assert_session->pageTextContains('Extra, Extra read all about it.');
134     $assert_session->pageTextNotContains('Placeholder for the "Extra label" field');
135     $assert_session->linkNotExists('Layout');
136
137     // Enable overrides.
138     $this->drupalPostForm("$field_ui_prefix/display/default", ['layout[allow_custom]' => TRUE], 'Save');
139     $this->drupalGet('node/1');
140
141     // Remove the section from the defaults.
142     $assert_session->linkExists('Layout');
143     $this->clickLink('Layout');
144     $assert_session->pageTextContains('Placeholder for the "Extra label" field');
145     $assert_session->linkExists('Remove section');
146     $this->clickLink('Remove section');
147     $page->pressButton('Remove');
148
149     // Add a new section.
150     $this->clickLink('Add Section');
151     $assert_session->linkExists('Two column');
152     $this->clickLink('Two column');
153     $assert_session->linkExists('Save Layout');
154     $this->clickLink('Save Layout');
155     $assert_session->pageTextNotContains('The first node body');
156     $assert_session->pageTextNotContains('Powered by Drupal');
157     $assert_session->pageTextNotContains('Extra, Extra read all about it.');
158     $assert_session->pageTextNotContains('Placeholder for the "Extra label" field');
159
160     // Assert that overrides cannot be turned off while overrides exist.
161     $this->drupalGet("$field_ui_prefix/display/default");
162     $assert_session->checkboxChecked('layout[allow_custom]');
163     $assert_session->fieldDisabled('layout[allow_custom]');
164
165     // Alter the defaults.
166     $this->drupalGet("$field_ui_prefix/display-layout/default");
167     $assert_session->linkExists('Add Block');
168     $this->clickLink('Add Block');
169     $assert_session->linkExists('Title');
170     $this->clickLink('Title');
171     $page->pressButton('Add Block');
172     // The title field is present.
173     $assert_session->elementExists('css', '.field--name-title');
174     $this->clickLink('Save Layout');
175
176     // View the other node, which is still using the defaults.
177     $this->drupalGet('node/2');
178     $assert_session->pageTextContains('The second node title');
179     $assert_session->pageTextContains('The second node body');
180     $assert_session->pageTextContains('Powered by Drupal');
181     $assert_session->pageTextContains('Extra, Extra read all about it.');
182     $assert_session->pageTextNotContains('Placeholder for the "Extra label" field');
183
184     // The overridden node does not pick up the changes to defaults.
185     $this->drupalGet('node/1');
186     $assert_session->elementNotExists('css', '.field--name-title');
187     $assert_session->pageTextNotContains('The first node body');
188     $assert_session->pageTextNotContains('Powered by Drupal');
189     $assert_session->pageTextNotContains('Extra, Extra read all about it.');
190     $assert_session->pageTextNotContains('Placeholder for the "Extra label" field');
191     $assert_session->linkExists('Layout');
192
193     // Reverting the override returns it to the defaults.
194     $this->clickLink('Layout');
195     $assert_session->linkExists('Add Block');
196     $this->clickLink('Add Block');
197     $assert_session->linkExists('ID');
198     $this->clickLink('ID');
199     $page->pressButton('Add Block');
200     // The title field is present.
201     $assert_session->elementExists('css', '.field--name-nid');
202     $assert_session->pageTextContains('ID');
203     $assert_session->pageTextContains('1');
204     $assert_session->linkExists('Revert to defaults');
205     $this->clickLink('Revert to defaults');
206     $page->pressButton('Revert');
207     $assert_session->pageTextContains('The layout has been reverted back to defaults.');
208     $assert_session->elementExists('css', '.field--name-title');
209     $assert_session->elementNotExists('css', '.field--name-nid');
210     $assert_session->pageTextContains('The first node body');
211     $assert_session->pageTextContains('Powered by Drupal');
212     $assert_session->pageTextContains('Placeholder for the "Extra label" field');
213
214     // Assert that overrides can be turned off now that all overrides are gone.
215     $this->drupalPostForm("$field_ui_prefix/display/default", ['layout[allow_custom]' => FALSE], 'Save');
216     $this->drupalGet('node/1');
217     $assert_session->linkNotExists('Layout');
218
219     // Add a new field.
220     $edit = [
221       'new_storage_type' => 'string',
222       'label' => 'My text field',
223       'field_name' => 'my_text',
224     ];
225     $this->drupalPostForm("$field_ui_prefix/fields/add-field", $edit, 'Save and continue');
226     $page->pressButton('Save field settings');
227     $page->pressButton('Save settings');
228     $this->drupalGet("$field_ui_prefix/display-layout/default");
229     $assert_session->pageTextContains('My text field');
230     $assert_session->elementExists('css', '.field--name-field-my-text');
231
232     // Delete the field.
233     $this->drupalPostForm("$field_ui_prefix/fields/node.bundle_with_section_field.field_my_text/delete", [], 'Delete');
234     $this->drupalGet("$field_ui_prefix/display-layout/default");
235     $assert_session->pageTextNotContains('My text field');
236     $assert_session->elementNotExists('css', '.field--name-field-my-text');
237   }
238
239   /**
240    * Tests that a non-default view mode works as expected.
241    */
242   public function testNonDefaultViewMode() {
243     $assert_session = $this->assertSession();
244     $page = $this->getSession()->getPage();
245
246     $this->drupalLogin($this->drupalCreateUser([
247       'configure any layout',
248       'administer node display',
249     ]));
250
251     $field_ui_prefix = 'admin/structure/types/manage/bundle_with_section_field';
252     // Allow overrides for the layout.
253     $this->drupalGet("$field_ui_prefix/display/default");
254     $page->checkField('layout[enabled]');
255     $page->pressButton('Save');
256     $page->checkField('layout[allow_custom]');
257     $page->pressButton('Save');
258
259     $this->clickLink('Manage layout');
260     // Confirm the body field only is shown once.
261     $assert_session->elementsCount('css', '.field--name-body', 1);
262     $this->clickLink('Cancel Layout');
263
264     $this->clickLink('Teaser');
265     // Enabling Layout Builder for the default mode does not affect the teaser.
266     $assert_session->addressEquals("$field_ui_prefix/display/teaser");
267     $assert_session->elementNotExists('css', '#layout-builder__layout');
268     $assert_session->checkboxNotChecked('layout[enabled]');
269     $page->checkField('layout[enabled]');
270     $page->pressButton('Save');
271     $assert_session->linkExists('Manage layout');
272     $page->clickLink('Manage layout');
273     // Confirm the body field only is shown once.
274     $assert_session->elementsCount('css', '.field--name-body', 1);
275
276     // Enable a disabled view mode.
277     $page->clickLink('Cancel Layout');
278     $assert_session->addressEquals("$field_ui_prefix/display/teaser");
279     $page->clickLink('Default');
280     $assert_session->addressEquals("$field_ui_prefix/display");
281     $assert_session->linkNotExists('Full content');
282     $page->checkField('display_modes_custom[full]');
283     $page->pressButton('Save');
284
285     $assert_session->linkExists('Full content');
286     $page->clickLink('Full content');
287     $assert_session->addressEquals("$field_ui_prefix/display/full");
288     $page->checkField('layout[enabled]');
289     $page->pressButton('Save');
290     $assert_session->linkExists('Manage layout');
291     $page->clickLink('Manage layout');
292     // Confirm the body field only is shown once.
293     $assert_session->elementsCount('css', '.field--name-body', 1);
294   }
295
296   /**
297    * Tests that component's dependencies are respected during removal.
298    */
299   public function testPluginDependencies() {
300     $assert_session = $this->assertSession();
301     $page = $this->getSession()->getPage();
302
303     $this->container->get('module_installer')->install(['menu_ui']);
304     $this->drupalLogin($this->drupalCreateUser([
305       'configure any layout',
306       'administer node display',
307       'administer menu',
308     ]));
309
310     // Create a new menu.
311     $this->drupalGet('admin/structure/menu/add');
312     $page->fillField('label', 'My Menu');
313     $page->fillField('id', 'mymenu');
314     $page->pressButton('Save');
315     $this->drupalGet('admin/structure/menu/add');
316     $page->fillField('label', 'My Menu');
317     $page->fillField('id', 'myothermenu');
318     $page->pressButton('Save');
319
320     $this->drupalPostForm('admin/structure/types/manage/bundle_with_section_field/display', ['layout[enabled]' => TRUE], 'Save');
321     $assert_session->linkExists('Manage layout');
322     $this->clickLink('Manage layout');
323     $assert_session->linkExists('Add Section');
324     $this->clickLink('Add Section');
325     $assert_session->linkExists('Layout plugin (with dependencies)');
326     $this->clickLink('Layout plugin (with dependencies)');
327     $assert_session->elementExists('css', '.layout--layout-test-dependencies-plugin');
328     $assert_session->elementExists('css', '.field--name-body');
329     $assert_session->linkExists('Save Layout');
330     $this->clickLink('Save Layout');
331     $this->drupalPostForm('admin/structure/menu/manage/myothermenu/delete', [], 'Delete');
332     $this->drupalGet('admin/structure/types/manage/bundle_with_section_field/display-layout/default');
333     $assert_session->elementNotExists('css', '.layout--layout-test-dependencies-plugin');
334     $assert_session->elementExists('css', '.field--name-body');
335
336     // Add a menu block.
337     $assert_session->linkExists('Add Block');
338     $this->clickLink('Add Block');
339     $assert_session->linkExists('My Menu');
340     $this->clickLink('My Menu');
341     $page->pressButton('Add Block');
342
343     // Add another block alongside the menu.
344     $assert_session->linkExists('Add Block');
345     $this->clickLink('Add Block');
346     $assert_session->linkExists('Powered by Drupal');
347     $this->clickLink('Powered by Drupal');
348     $page->pressButton('Add Block');
349
350     // Assert that the blocks are visible, and save the layout.
351     $assert_session->pageTextContains('Powered by Drupal');
352     $assert_session->pageTextContains('My Menu');
353     $assert_session->elementExists('css', '.block.menu--mymenu');
354     $assert_session->linkExists('Save Layout');
355     $this->clickLink('Save Layout');
356
357     // Delete the menu.
358     $this->drupalPostForm('admin/structure/menu/manage/mymenu/delete', [], 'Delete');
359
360     // Ensure that the menu block is gone, but that the other block remains.
361     $this->drupalGet('admin/structure/types/manage/bundle_with_section_field/display-layout/default');
362     $assert_session->pageTextContains('Powered by Drupal');
363     $assert_session->pageTextNotContains('My Menu');
364     $assert_session->elementNotExists('css', '.block.menu--mymenu');
365   }
366
367   /**
368    * Tests the interaction between full and default view modes.
369    *
370    * @see \Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage::getDefaultSectionStorage()
371    */
372   public function testLayoutBuilderUiFullViewMode() {
373     $assert_session = $this->assertSession();
374     $page = $this->getSession()->getPage();
375
376     $this->drupalLogin($this->drupalCreateUser([
377       'configure any layout',
378       'administer node display',
379       'administer node fields',
380     ]));
381
382     $field_ui_prefix = 'admin/structure/types/manage/bundle_with_section_field';
383     // Allow overrides for the layout.
384     $this->drupalPostForm("$field_ui_prefix/display/default", ['layout[enabled]' => TRUE], 'Save');
385     $this->drupalPostForm("$field_ui_prefix/display/default", ['layout[allow_custom]' => TRUE], 'Save');
386
387     // Customize the default view mode.
388     $this->drupalGet("$field_ui_prefix/display-layout/default");
389     $this->clickLink('Add Block');
390     $this->clickLink('Powered by Drupal');
391     $page->fillField('settings[label]', 'This is the default view mode');
392     $page->checkField('settings[label_display]');
393     $page->pressButton('Add Block');
394     $assert_session->pageTextContains('This is the default view mode');
395     $this->clickLink('Save Layout');
396
397     // The default view mode is used for both the node display and layout UI.
398     $this->drupalGet('node/1');
399     $assert_session->pageTextContains('This is the default view mode');
400     $this->drupalGet('node/1/layout');
401     $assert_session->pageTextContains('This is the default view mode');
402     $this->clickLink('Cancel Layout');
403
404     // Enable the full view mode and customize it.
405     $this->drupalPostForm("$field_ui_prefix/display/default", ['display_modes_custom[full]' => TRUE], 'Save');
406     $this->drupalPostForm("$field_ui_prefix/display/full", ['layout[enabled]' => TRUE], 'Save');
407     $this->drupalGet("$field_ui_prefix/display-layout/full");
408     $this->clickLink('Add Block');
409     $this->clickLink('Powered by Drupal');
410     $page->fillField('settings[label]', 'This is the full view mode');
411     $page->checkField('settings[label_display]');
412     $page->pressButton('Add Block');
413     $assert_session->pageTextContains('This is the full view mode');
414     $this->clickLink('Save Layout');
415
416     // The full view mode is now used for both the node display and layout UI.
417     $this->drupalGet('node/1');
418     $assert_session->pageTextContains('This is the full view mode');
419     $this->drupalGet('node/1/layout');
420     $assert_session->pageTextContains('This is the full view mode');
421     $this->clickLink('Cancel Layout');
422
423     // Disable the full view mode, the default should be used again.
424     $this->drupalPostForm("$field_ui_prefix/display/default", ['display_modes_custom[full]' => FALSE], 'Save');
425     $this->drupalGet('node/1');
426     $assert_session->pageTextContains('This is the default view mode');
427     $this->drupalGet('node/1/layout');
428     $assert_session->pageTextContains('This is the default view mode');
429     $this->clickLink('Cancel Layout');
430   }
431
432   /**
433    * {@inheritdoc}
434    */
435   public function testLayoutBuilderChooseBlocksAlter() {
436     // See layout_builder_test_plugin_filter_block__layout_builder_alter().
437     $assert_session = $this->assertSession();
438
439     $this->drupalLogin($this->drupalCreateUser([
440       'configure any layout',
441       'administer node display',
442       'administer node fields',
443     ]));
444
445     // From the manage display page, go to manage the layout.
446     $this->drupalPostForm('admin/structure/types/manage/bundle_with_section_field/display/default', ['layout[enabled]' => TRUE], 'Save');
447     $assert_session->linkExists('Manage layout');
448     $this->clickLink('Manage layout');
449
450     // Add a new block.
451     $this->clickLink('Add Block');
452
453     // Verify that blocks not modified are present.
454     $assert_session->linkExists('Powered by Drupal');
455     $assert_session->linkExists('Default revision');
456
457     // Verify that blocks explicitly removed are not present.
458     $assert_session->linkNotExists('Help');
459     $assert_session->linkNotExists('Sticky at top of lists');
460
461     // Verify that Changed block is not present on first section.
462     $assert_session->linkNotExists('Changed');
463
464     // Go back to Manage layout.
465     $this->drupalGet('admin/structure/types/manage/bundle_with_section_field/display/default');
466     $this->clickLink('Manage layout');
467
468     // Add a new section.
469     $this->clickLink('Add Section', 1);
470     $assert_session->linkExists('Two column');
471     $this->clickLink('Two column');
472
473     // Add a new block to second section.
474     $this->clickLink('Add Block', 1);
475
476     // Verify that Changed block is present on second section.
477     $assert_session->linkExists('Changed');
478   }
479
480   /**
481    * Tests that deleting a View block used in Layout Builder works.
482    */
483   public function testDeletedView() {
484     $assert_session = $this->assertSession();
485     $page = $this->getSession()->getPage();
486
487     $this->drupalLogin($this->drupalCreateUser([
488       'configure any layout',
489       'administer node display',
490     ]));
491
492     $field_ui_prefix = 'admin/structure/types/manage/bundle_with_section_field';
493     // Enable overrides.
494     $this->drupalPostForm("$field_ui_prefix/display/default", ['layout[enabled]' => TRUE], 'Save');
495     $this->drupalPostForm("$field_ui_prefix/display/default", ['layout[allow_custom]' => TRUE], 'Save');
496     $this->drupalGet('node/1');
497
498     $assert_session->linkExists('Layout');
499     $this->clickLink('Layout');
500     $this->clickLink('Add Block');
501     $this->clickLink('Test Block View');
502     $page->pressButton('Add Block');
503
504     $assert_session->pageTextContains('Test Block View');
505     $assert_session->elementExists('css', '.block-views-blocktest-block-view-block-1');
506     $this->clickLink('Save Layout');
507     $assert_session->pageTextContains('Test Block View');
508     $assert_session->elementExists('css', '.block-views-blocktest-block-view-block-1');
509
510     View::load('test_block_view')->delete();
511     $this->drupalGet('node/1');
512     // Node can be loaded after deleting the View.
513     $assert_session->pageTextContains(Node::load(1)->getTitle());
514     $assert_session->pageTextNotContains('Test Block View');
515   }
516
517   /**
518    * Tests the usage of placeholders for empty blocks.
519    *
520    * @see \Drupal\Core\Block\BlockPluginInterface::getPlaceholderString()
521    * @see \Drupal\layout_builder\EventSubscriber\BlockComponentRenderArray::onBuildRender()
522    */
523   public function testBlockPlaceholder() {
524     $assert_session = $this->assertSession();
525     $page = $this->getSession()->getPage();
526
527     $this->drupalLogin($this->drupalCreateUser([
528       'configure any layout',
529       'administer node display',
530     ]));
531
532     $field_ui_prefix = 'admin/structure/types/manage/bundle_with_section_field';
533     $this->drupalPostForm("$field_ui_prefix/display/default", ['layout[enabled]' => TRUE], 'Save');
534
535     // Customize the default view mode.
536     $this->drupalGet("$field_ui_prefix/display-layout/default");
537
538     // Add a block whose content is controlled by state and is empty by default.
539     $this->clickLink('Add Block');
540     $this->clickLink('Test block caching');
541     $page->fillField('settings[label]', 'The block label');
542     $page->pressButton('Add Block');
543
544     $block_content = 'I am content';
545     $placeholder_content = 'Placeholder for the "The block label" block';
546
547     // The block placeholder is displayed and there is no content.
548     $assert_session->pageTextContains($placeholder_content);
549     $assert_session->pageTextNotContains($block_content);
550
551     // Set block content and reload the page.
552     \Drupal::state()->set('block_test.content', $block_content);
553     $this->getSession()->reload();
554
555     // The block placeholder is no longer displayed and the content is visible.
556     $assert_session->pageTextNotContains($placeholder_content);
557     $assert_session->pageTextContains($block_content);
558   }
559
560   /**
561    * Tests the Block UI when Layout Builder is installed.
562    */
563   public function testBlockUiListing() {
564     $assert_session = $this->assertSession();
565     $page = $this->getSession()->getPage();
566
567     $this->drupalLogin($this->drupalCreateUser([
568       'administer blocks',
569     ]));
570
571     $this->drupalGet('admin/structure/block');
572     $page->clickLink('Place block');
573
574     // Ensure that blocks expected to appear are available.
575     $assert_session->pageTextContains('Test HTML block');
576     $assert_session->pageTextContains('Block test');
577     // Ensure that blocks not expected to appear are not available.
578     $assert_session->pageTextNotContains('Body');
579     $assert_session->pageTextNotContains('Content fields');
580   }
581
582 }