1 layout.test LayoutInterfaceTest::testBlockBasics()

Add and remove blocks from a custom layout path.

File

core/modules/layout/tests/layout.test, line 243
Tests for the Layout module.

Class

LayoutInterfaceTest
Tests the interface for adding, removing, and moving blocks.

Code

function testBlockBasics() {
  $this->backdropGet('admin/structure/layouts');
  $this->clickLink(t('Add layout'));

  // Create a new layout at a new path.
  $layout_title = $this->randomName();
  $layout_name = strtolower($layout_title);
  $layout_url = 'layout-test-path';
  $edit = array(
    'title' => $layout_title,
    'name' => $layout_name,
    'layout_template' => 'moscone_flipped',
    'path' => $layout_url,
  );
  $this->backdropPost(NULL, $edit, t('Create layout'));

  // We should be taken to the layout content page next.
  $this->assertText(t('Layout created. Blocks may now be added to this layout.'));

  // Check that a block that requires contexts is not shown.
  $this->assertNoLink(t('Main page content'));
  $this->assertNoLink(t('Layout bar block'));

  // Add a block to the sidebar.
  $this->clickLink(t('Add block'), 3);
  $this->assertText(t('A testing block for layouts.'));
  $this->clickLink(t('Layout foo block'));
  $edit = array(
    'block_settings[count]' => 5,
  );
  $this->backdropPost(NULL, $edit, t('Add block'));

  // Record the UUID for the newly added block.
  $last_block = $this->xpath('(//*[contains(@class,:region)]//*[@data-block-id])[last()]', array(
    ':region' => 'l-sidebar',
  ));
  $block_uuid = (string) $last_block[0]['data-block-id'];
  $block_edit_url = 'admin/structure/layouts/manage/' . $layout_name . '/configure-block/editor/' . $block_uuid;

  // Check the admin label and description.
  $elements = $this->xpath('//*[contains(@id,:id)]//*[contains(@class,:class)]//span[normalize-space()=:title]', array(
    ':id' => 'layout-editor-block-' . $block_uuid,
    ':class' => 'layout-editor-block-title',
    ':title' => t('Layout foo block'),
  ));
  $this->assertEqual(count($elements), 1, 'The sample block label was found.');
  $elements = $this->xpath('//*[contains(@id,:id)]//*[contains(@class,:class)]//*[normalize-space()=:description]', array(
    ':id' => 'layout-editor-block-' . $block_uuid,
    ':class' => 'layout-editor-block-content',
    ':description' => t('A testing block for layouts.'),
  ));
  $this->assertEqual(count($elements), 1, 'The sample block description was found.');

  // Change the label and description.
  $block_new_label = $this->randomName();
  $block_new_description = $this->randomName();
  $edit = array(
    'admin_label' => $block_new_label,
    'admin_description' => $block_new_description,
  );
  $this->backdropPost($block_edit_url, $edit, t('Update block'));

  // Check the new admin label and description.
  $elements = $this->xpath('//*[contains(@id,:id)]//*[contains(@class,:class)]//span[normalize-space()=:title]', array(
    ':id' => 'layout-editor-block-' . $block_uuid,
    ':class' => 'layout-editor-block-title',
    ':title' => $block_new_label,
  ));
  $this->assertEqual(count($elements), 1, 'The sample block label was found.');
  $elements = $this->xpath('//*[contains(@id,:id)]//*[contains(@class,:class) and contains(text(), :description)]', array(
    ':id' => 'layout-editor-block-' . $block_uuid,
    ':class' => 'layout-editor-block-content',
    ':description' => $block_new_description,
  ));
  $this->assertEqual(count($elements), 1, 'The sample block description was changed.');

  // Save the layout.
  $this->backdropPost(NULL, array(), t('Save layout'));

  // Check that the layout is in the listing of layouts.
  $this->backdropGet('admin/structure/layouts');
  $this->assertText(check_plain($layout_title));

  // Go to the the layout path and confirm the block exists, has the right
  // setting, and is the right place.
  $this->backdropGet($layout_url);
  $this->assertText('Foo subject');
  $this->assertText(format_string('The setting of count is @setting.', array('@setting' => 5)));
  $elements = $this->xpath('//*[contains(@class,:region)]//*[contains(@class,:block)]', array(
    ':region' => 'l-sidebar',
    ':block' => 'block-layout-test-foo',
  ));
  $this->assertEqual(count($elements), 1, 'The sample block was found in the sidebar.');

  // Try updating the block title to use a custom string.
  $block_new_title = $this->randomName();
  $edit = array(
    'title_display' => LAYOUT_TITLE_CUSTOM,
    'title' => $block_new_title,
  );
  $this->backdropPost($block_edit_url, $edit, t('Update block'));
  $this->backdropPost(NULL, array(), t('Save layout'));
  $this->backdropGet($layout_url);
  $this->assertText(check_plain($block_new_title));

  // Set the block title to nothing.
  $edit = array(
    'title_display' => LAYOUT_TITLE_NONE,
  );
  $this->backdropPost($block_edit_url, $edit, t('Update block'));
  $this->backdropPost(NULL, array(), t('Save layout'));
  $this->backdropGet($layout_url);
  $this->assertNoText('Foo subject');
  $this->assertNoText($block_new_title);

  // Set the block title back to normal and set a special block class.
  $custom_class = $this->randomName();
  $edit = array(
    'title_display' => LAYOUT_TITLE_DEFAULT,
    'style_settings[classes]' => $custom_class,
  );
  $this->backdropPost($block_edit_url, $edit, t('Update block'));
  $this->backdropPost(NULL, array(), t('Save layout'));

  $this->backdropGet($layout_url);
  $this->assertText('Foo subject');
  $this->assertNoText($block_new_title);
  $block_element = $this->xpath('(//*[contains(@class,:region)]//*[contains(@class,:block)])[contains(@class,:custom-class)]', array(
    ':region' => 'l-sidebar',
    ':block' => 'block-layout-test-foo',
    ':custom-class' => $custom_class,
  ));
  $this->assertEqual(count($block_element), 1, 'The sample block was found in the sidebar.');

  // Use the dynamic block style. Save once to update the form (usually done
  // via AJAX) then, edit and save again with the dynamic settings.
  $title_class = $this->randomName();
  $content_class = $this->randomName();
  $edit = array(
    'style' => 'dynamic',
  );
  $this->backdropPost($block_edit_url, $edit, t('Update block'));
  $edit = array(
    'style_settings[wrapper_tag]' => 'aside',
    'style_settings[title_tag]' => 'h3',
    'style_settings[title_classes]' => $title_class,
    'style_settings[content_tag]' => 'p',
    'style_settings[content_classes]' => $content_class,
  );
  $this->backdropPost($block_edit_url, $edit, t('Update block'));
  $this->backdropPost(NULL, array(), t('Save layout'));

  $this->backdropGet($layout_url);
  $block_element = $this->xpath('(//*[contains(@class,:region)]//aside[contains(@class,:block)])[contains(@class,:custom-class)]', array(
    ':region' => 'l-sidebar',
    ':block' => 'block-layout-test-foo',
    ':custom-class' => $custom_class,
  ));
  $this->assertEqual(count($block_element), 1, 'The sample block was found in the sidebar as an aside tag.');
  if ($block_element) {
    $title_element = $block_element[0]->xpath('h3');
    $content_element = $block_element[0]->xpath('p');
    $this->assertEqual(count($title_element), 1, 'The sample block has the correct H3 heading tag.');
    $this->assertEqual(count($content_element), 1, 'The sample block has the correct P content tag.');
    $this->assertEqual($title_element[0]['class'], $title_class, 'The sample block title has the correct class.');
    $this->assertEqual($content_element[0]['class'], $content_class, 'The sample block content has the correct class.');
  }

  // Try injecting XSS into the classes.
  $xss = '"><svg onload="alert(\'XSS hole\')">';
  // The filtered string after running through backdrop_html_class().
  // cspell:disable-next-line
  $filtered_xss = 'svg onloadalertXSS hole';
  $edit = array(
    'style_settings[classes]' => $xss,
    'style_settings[title_classes]' => $xss,
    'style_settings[content_classes]' => $xss,
  );
  $this->backdropPost($block_edit_url, $edit, t('Update block'));
  $this->backdropPost(NULL, array(), t('Save layout'));

  $this->backdropGet($layout_url);
  $this->assertNoRaw($xss);
  $this->assertRaw($filtered_xss);

  // Try moving the block to a different position within the layout.
  $edit = array(
    'content[positions][content]' => $block_uuid,
    'content[positions][sidebar]' => '',
  );
  $this->backdropPost('admin/structure/layouts/manage/' . $layout_name, $edit, t('Save layout'));
  $this->backdropGet($layout_url);
  $block_element = $this->xpath('//*[contains(@class,:region)]//*[contains(@class,:block)]', array(
    ':region' => 'l-content',
    ':block' => 'block-layout-test-foo',
  ));
  $this->assertEqual(count($block_element), 1, 'The sample block was found in the content area after moving it from the sidebar.');

  // Move the block via the block configuration form.
  $edit = array(
    'region' => 'footer',
  );
  $this->backdropPost($block_edit_url, $edit, t('Update block'));
  $this->backdropPost(NULL, array(), t('Save layout'));

  $this->backdropGet($layout_url);
  $block_element = $this->xpath('(//*[contains(@class,:region)]//*[contains(@class,:block)])', array(
    ':region' => 'l-footer',
    ':block' => 'block-layout-test-foo',
  ));
  $this->assertEqual(count($block_element), 1, 'The sample block was found in the footer after moving via block form.');

  // Try moving the block into the sidebar again via the API.
  backdrop_static_reset();
  $layout = layout_load($layout_name);
  $layout->setBlockPosition($block_uuid, 'sidebar');
  $layout->save();

  $this->backdropGet($layout_url);
  $block_element = $this->xpath('(//*[contains(@class,:region)]//*[contains(@class,:block)])', array(
    ':region' => 'l-sidebar',
    ':block' => 'block-layout-test-foo',
  ));
  $this->assertEqual(count($block_element), 1, 'The sample block was found in the sidebar after moving via the API.');

  // With all the manipulations we've performed, make sure that the block is
  // still only shown once, and did not end up in multiple regions on the page
  // by accident.
  $block_element = $this->xpath('//*[contains(@class,:block)]', array(
    ':block' => 'block-layout-test-foo',
  ));
  $this->assertEqual(count($block_element), 1, 'The sample block is only displayed once after moving it.');

  // Disable the block.
  $this->backdropGet('admin/structure/layouts/manage/' . $layout_name);
  $disable_link = $this->xpath('//*[@data-block-id=:uuid]//a[contains(@class,"disable-block")]', array(
    ':uuid' => $block_uuid,
  ));
  $disable_url_parts = backdrop_parse_url($disable_link[0]['href']);
  $this->backdropGet($disable_url_parts['path'], $disable_url_parts);

  $this->assertText(t('Block "@title" disabled.', array('@title' => $block_new_label)));

  // The block is still present in the UI.
  $elements = $this->xpath('//*[contains(@id,:id)]//*[contains(@class,:class)]//span[normalize-space()=:title]', array(
    ':id' => 'layout-editor-block-' . $block_uuid,
    ':class' => 'layout-editor-block-title',
    ':title' => $block_new_label . ' (Disabled)',
  ));
  $this->assertEqual(count($elements), 1, 'The sample block label was found.');
  $elements = $this->xpath('//*[contains(@id,:id)]//*[contains(@class,:class) and contains(text(), :description)]', array(
    ':id' => 'layout-editor-block-' . $block_uuid,
    ':class' => 'layout-editor-block-content',
    ':description' => $block_new_description,
  ));
  $this->assertEqual(count($elements), 1, 'The sample block description was changed.');

  $this->backdropPost(NULL, array(), t('Save layout'));

  // But is gone from the layout page.
  $this->backdropGet($layout_url);
  $this->assertNoText('Foo subject');
  $block_element = $this->xpath('//*[contains(@class,:block)]', array(
    ':block' => 'block-layout-test-foo',
  ));
  $this->assertEqual(count($block_element), 0, 'The sample block is not visible on the page.');

  // Re-enable the block.
  $this->backdropGet('admin/structure/layouts/manage/' . $layout_name);
  $this->backdropGet($disable_url_parts['path'], $disable_url_parts);

  $this->assertText(t('Block "@title" disabled.', array('@title' => $block_new_label)));

  // The block is still present in the UI.
  $elements = $this->xpath('//*[contains(@id,:id)]//*[contains(@class,:class)]//span[normalize-space()=:title]', array(
    ':id' => 'layout-editor-block-' . $block_uuid,
    ':class' => 'layout-editor-block-title',
    ':title' => $block_new_label,
  ));
  $this->assertEqual(count($elements), 1, 'The sample block label was found.');
  $elements = $this->xpath('//*[contains(@id,:id)]//*[contains(@class,:class) and contains(text(), :description)]', array(
    ':id' => 'layout-editor-block-' . $block_uuid,
    ':class' => 'layout-editor-block-content',
    ':description' => $block_new_description,
  ));
  $this->assertEqual(count($elements), 1, 'The sample block description was changed.');

  $this->backdropPost(NULL, array(), t('Save layout'));

  // Block is back on the layout page.
  $this->backdropGet($layout_url);
  $this->assertText('Foo subject');
  $block_element = $this->xpath('//*[contains(@class,:block)]', array(
    ':block' => 'block-layout-test-foo',
  ));
  $this->assertEqual(count($block_element), 1, 'The sample block is again visible on the page.');

  // Finally, try removing the block.
  $this->backdropGet('admin/structure/layouts/manage/' . $layout_name);
  $remove_link = $this->xpath('//*[@data-block-id=:uuid]//a[contains(@class,"remove-block")]', array(
    ':uuid' => $block_uuid,
  ));
  $remove_url_parts = backdrop_parse_url($remove_link[0]['href']);
  $this->backdropGet($remove_url_parts['path'], $remove_url_parts);
  $this->backdropPost(NULL, array(), t('Save layout'));

  $this->backdropGet($layout_url);
  $this->assertNoText('Foo subject');
  $block_element = $this->xpath('//*[contains(@class,:block)]', array(
    ':block' => 'block-layout-test-foo',
  ));
  $this->assertEqual(count($block_element), 0, 'The sample block has been removed.');

  // Delete the layout to prevent it interfering with following tests.
  $this->backdropPost('admin/structure/layouts/manage/' . $layout_name . '/delete', array(), t('Delete layout'));
}