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