forgot some core files

This commit is contained in:
2018-10-23 12:03:58 +02:00
parent 5c71ef4c46
commit cc9fe30fc5
4 changed files with 1323 additions and 0 deletions
@@ -0,0 +1,471 @@
<?php
namespace Drupal\node\Tests;
use Drupal\Core\Url;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
use Drupal\Component\Serialization\Json;
/**
* Create a node with revisions and test viewing, saving, reverting, and
* deleting revisions for users with access for this content type.
*
* @group node
*/
class NodeRevisionsTest extends NodeTestBase {
/**
* An array of node revisions.
*
* @var \Drupal\node\NodeInterface[]
*/
protected $nodes;
/**
* Revision log messages.
*
* @var array
*/
protected $revisionLogs;
/**
* {@inheritdoc}
*/
public static $modules = ['node', 'contextual', 'datetime', 'language', 'content_translation'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Enable additional languages.
ConfigurableLanguage::createFromLangcode('de')->save();
ConfigurableLanguage::createFromLangcode('it')->save();
$field_storage_definition = [
'field_name' => 'untranslatable_string_field',
'entity_type' => 'node',
'type' => 'string',
'cardinality' => 1,
'translatable' => FALSE,
];
$field_storage = FieldStorageConfig::create($field_storage_definition);
$field_storage->save();
$field_definition = [
'field_storage' => $field_storage,
'bundle' => 'page',
];
$field = FieldConfig::create($field_definition);
$field->save();
// Enable translation for page nodes.
\Drupal::service('content_translation.manager')->setEnabled('node', 'page', TRUE);
// Create and log in user.
$web_user = $this->drupalCreateUser(
[
'view page revisions',
'revert page revisions',
'delete page revisions',
'edit any page content',
'delete any page content',
'access contextual links',
'translate any entity',
'administer content types',
]
);
$this->drupalLogin($web_user);
// Create initial node.
$node = $this->drupalCreateNode();
$settings = get_object_vars($node);
$settings['revision'] = 1;
$settings['isDefaultRevision'] = TRUE;
$nodes = [];
$logs = [];
// Get original node.
$nodes[] = clone $node;
// Create three revisions.
$revision_count = 3;
for ($i = 0; $i < $revision_count; $i++) {
$logs[] = $node->revision_log = $this->randomMachineName(32);
// Create revision with a random title and body and update variables.
$node->title = $this->randomMachineName();
$node->body = [
'value' => $this->randomMachineName(32),
'format' => filter_default_format(),
];
$node->untranslatable_string_field->value = $this->randomString();
$node->setNewRevision();
// Edit the 1st and 2nd revision with a different user.
if ($i < 2) {
$editor = $this->drupalCreateUser();
$node->setRevisionUserId($editor->id());
}
else {
$node->setRevisionUserId($web_user->id());
}
$node->save();
// Make sure we get revision information.
$node = Node::load($node->id());
$nodes[] = clone $node;
}
$this->nodes = $nodes;
$this->revisionLogs = $logs;
}
/**
* Checks node revision related operations.
*/
public function testRevisions() {
$node_storage = $this->container->get('entity.manager')->getStorage('node');
$nodes = $this->nodes;
$logs = $this->revisionLogs;
// Get last node for simple checks.
$node = $nodes[3];
// Confirm the correct revision text appears on "view revisions" page.
$this->drupalGet("node/" . $node->id() . "/revisions/" . $node->getRevisionId() . "/view");
$this->assertText($node->body->value, 'Correct text displays for version.');
// Confirm the correct log message appears on "revisions overview" page.
$this->drupalGet("node/" . $node->id() . "/revisions");
foreach ($logs as $revision_log) {
$this->assertText($revision_log, 'Revision log message found.');
}
// Original author, and editor names should appear on revisions overview.
$web_user = $nodes[0]->revision_uid->entity;
$this->assertText(t('by @name', ['@name' => $web_user->getAccountName()]));
$editor = $nodes[2]->revision_uid->entity;
$this->assertText(t('by @name', ['@name' => $editor->getAccountName()]));
// Confirm that this is the default revision.
$this->assertTrue($node->isDefaultRevision(), 'Third node revision is the default one.');
// Confirm that the "Edit" and "Delete" contextual links appear for the
// default revision.
$ids = ['node:node=' . $node->id() . ':changed=' . $node->getChangedTime()];
$json = $this->renderContextualLinks($ids, 'node/' . $node->id());
$this->verbose($json[$ids[0]]);
$expected = '<li class="entitynodeedit-form"><a href="' . base_path() . 'node/' . $node->id() . '/edit">Edit</a></li>';
$this->assertTrue(strstr($json[$ids[0]], $expected), 'The "Edit" contextual link is shown for the default revision.');
$expected = '<li class="entitynodedelete-form"><a href="' . base_path() . 'node/' . $node->id() . '/delete">Delete</a></li>';
$this->assertTrue(strstr($json[$ids[0]], $expected), 'The "Delete" contextual link is shown for the default revision.');
// Confirm that revisions revert properly.
$this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionid() . "/revert", [], t('Revert'));
$this->assertRaw(t('@type %title has been reverted to the revision from %revision-date.', [
'@type' => 'Basic page',
'%title' => $nodes[1]->label(),
'%revision-date' => format_date($nodes[1]->getRevisionCreationTime()),
]), 'Revision reverted.');
$node_storage->resetCache([$node->id()]);
$reverted_node = $node_storage->load($node->id());
$this->assertTrue(($nodes[1]->body->value == $reverted_node->body->value), 'Node reverted correctly.');
// Confirm the revision author is the user performing the revert.
$this->assertTrue($reverted_node->getRevisionUserId() == $this->loggedInUser->id(), 'Node revision author is user performing revert.');
// And that its not the revision author.
$this->assertTrue($reverted_node->getRevisionUserId() != $nodes[1]->getRevisionUserId(), 'Node revision author is not original revision author.');
// Confirm that this is not the default version.
$node = node_revision_load($node->getRevisionId());
$this->assertFalse($node->isDefaultRevision(), 'Third node revision is not the default one.');
// Confirm that "Edit" and "Delete" contextual links don't appear for
// non-default revision.
$ids = ['node_revision::node=' . $node->id() . '&node_revision=' . $node->getRevisionId() . ':'];
$json = $this->renderContextualLinks($ids, 'node/' . $node->id() . '/revisions/' . $node->getRevisionId() . '/view');
$this->verbose($json[$ids[0]]);
$this->assertFalse(strstr($json[$ids[0]], '<li class="entitynodeedit-form">'), 'The "Edit" contextual link is not shown for a non-default revision.');
$this->assertFalse(strstr($json[$ids[0]], '<li class="entitynodedelete-form">'), 'The "Delete" contextual link is not shown for a non-default revision.');
// Confirm revisions delete properly.
$this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[1]->getRevisionId() . "/delete", [], t('Delete'));
$this->assertRaw(t('Revision from %revision-date of @type %title has been deleted.', [
'%revision-date' => format_date($nodes[1]->getRevisionCreationTime()),
'@type' => 'Basic page',
'%title' => $nodes[1]->label(),
]), 'Revision deleted.');
$this->assertTrue(db_query('SELECT COUNT(vid) FROM {node_revision} WHERE nid = :nid and vid = :vid', [':nid' => $node->id(), ':vid' => $nodes[1]->getRevisionId()])->fetchField() == 0, 'Revision not found.');
$this->assertTrue(db_query('SELECT COUNT(vid) FROM {node_field_revision} WHERE nid = :nid and vid = :vid', [':nid' => $node->id(), ':vid' => $nodes[1]->getRevisionId()])->fetchField() == 0, 'Field revision not found.');
// Set the revision timestamp to an older date to make sure that the
// confirmation message correctly displays the stored revision date.
$old_revision_date = REQUEST_TIME - 86400;
db_update('node_revision')
->condition('vid', $nodes[2]->getRevisionId())
->fields([
'revision_timestamp' => $old_revision_date,
])
->execute();
$this->drupalPostForm("node/" . $node->id() . "/revisions/" . $nodes[2]->getRevisionId() . "/revert", [], t('Revert'));
$this->assertRaw(t('@type %title has been reverted to the revision from %revision-date.', [
'@type' => 'Basic page',
'%title' => $nodes[2]->label(),
'%revision-date' => format_date($old_revision_date),
]));
// Make a new revision and set it to not be default.
// This will create a new revision that is not "front facing".
$new_node_revision = clone $node;
$new_body = $this->randomMachineName();
$new_node_revision->body->value = $new_body;
// Save this as a non-default revision.
$new_node_revision->setNewRevision();
$new_node_revision->isDefaultRevision = FALSE;
$new_node_revision->save();
$this->drupalGet('node/' . $node->id());
$this->assertNoText($new_body, 'Revision body text is not present on default version of node.');
// Verify that the new body text is present on the revision.
$this->drupalGet("node/" . $node->id() . "/revisions/" . $new_node_revision->getRevisionId() . "/view");
$this->assertText($new_body, 'Revision body text is present when loading specific revision.');
// Verify that the non-default revision vid is greater than the default
// revision vid.
$default_revision = db_select('node', 'n')
->fields('n', ['vid'])
->condition('nid', $node->id())
->execute()
->fetchCol();
$default_revision_vid = $default_revision[0];
$this->assertTrue($new_node_revision->getRevisionId() > $default_revision_vid, 'Revision vid is greater than default revision vid.');
// Create an 'EN' node with a revision log message.
$node = $this->drupalCreateNode();
$node->title = 'Node title in EN';
$node->revision_log = 'Simple revision message (EN)';
$node->save();
$this->drupalGet("node/" . $node->id() . "/revisions");
$this->assertResponse(403);
// Create a new revision and new log message.
$node = Node::load($node->id());
$node->body->value = 'New text (EN)';
$node->revision_log = 'New revision message (EN)';
$node->setNewRevision();
$node->save();
// Check both revisions are shown on the node revisions overview page.
$this->drupalGet("node/" . $node->id() . "/revisions");
$this->assertText('Simple revision message (EN)');
$this->assertText('New revision message (EN)');
// Create an 'EN' node with a revision log message.
$node = $this->drupalCreateNode();
$node->langcode = 'en';
$node->title = 'Node title in EN';
$node->revision_log = 'Simple revision message (EN)';
$node->save();
$this->drupalGet("node/" . $node->id() . "/revisions");
$this->assertResponse(403);
// Add a translation in 'DE' and create a new revision and new log message.
$translation = $node->addTranslation('de');
$translation->title->value = 'Node title in DE';
$translation->body->value = 'New text (DE)';
$translation->revision_log = 'New revision message (DE)';
$translation->setNewRevision();
$translation->save();
// View the revision UI in 'IT', only the original node revision is shown.
$this->drupalGet("it/node/" . $node->id() . "/revisions");
$this->assertText('Simple revision message (EN)');
$this->assertNoText('New revision message (DE)');
// View the revision UI in 'DE', only the translated node revision is shown.
$this->drupalGet("de/node/" . $node->id() . "/revisions");
$this->assertNoText('Simple revision message (EN)');
$this->assertText('New revision message (DE)');
// View the revision UI in 'EN', only the original node revision is shown.
$this->drupalGet("node/" . $node->id() . "/revisions");
$this->assertText('Simple revision message (EN)');
$this->assertNoText('New revision message (DE)');
}
/**
* Checks that revisions are correctly saved without log messages.
*/
public function testNodeRevisionWithoutLogMessage() {
$node_storage = $this->container->get('entity.manager')->getStorage('node');
// Create a node with an initial log message.
$revision_log = $this->randomMachineName(10);
$node = $this->drupalCreateNode(['revision_log' => $revision_log]);
// Save over the same revision and explicitly provide an empty log message
// (for example, to mimic the case of a node form submitted with no text in
// the "log message" field), and check that the original log message is
// preserved.
$new_title = $this->randomMachineName(10) . 'testNodeRevisionWithoutLogMessage1';
$node = clone $node;
$node->title = $new_title;
$node->revision_log = '';
$node->setNewRevision(FALSE);
$node->save();
$this->drupalGet('node/' . $node->id());
$this->assertText($new_title, 'New node title appears on the page.');
$node_storage->resetCache([$node->id()]);
$node_revision = $node_storage->load($node->id());
$this->assertEqual($node_revision->revision_log->value, $revision_log, 'After an existing node revision is re-saved without a log message, the original log message is preserved.');
// Create another node with an initial revision log message.
$node = $this->drupalCreateNode(['revision_log' => $revision_log]);
// Save a new node revision without providing a log message, and check that
// this revision has an empty log message.
$new_title = $this->randomMachineName(10) . 'testNodeRevisionWithoutLogMessage2';
$node = clone $node;
$node->title = $new_title;
$node->setNewRevision();
$node->revision_log = NULL;
$node->save();
$this->drupalGet('node/' . $node->id());
$this->assertText($new_title, 'New node title appears on the page.');
$node_storage->resetCache([$node->id()]);
$node_revision = $node_storage->load($node->id());
$this->assertTrue(empty($node_revision->revision_log->value), 'After a new node revision is saved with an empty log message, the log message for the node is empty.');
}
/**
* Gets server-rendered contextual links for the given contextual links IDs.
*
* @param string[] $ids
* An array of contextual link IDs.
* @param string $current_path
* The Drupal path for the page for which the contextual links are rendered.
*
* @return string
* The decoded JSON response body.
*/
protected function renderContextualLinks(array $ids, $current_path) {
$post = [];
for ($i = 0; $i < count($ids); $i++) {
$post['ids[' . $i . ']'] = $ids[$i];
}
$response = $this->drupalPost('contextual/render', 'application/json', $post, ['query' => ['destination' => $current_path]]);
return Json::decode($response);
}
/**
* Tests the revision translations are correctly reverted.
*/
public function testRevisionTranslationRevert() {
// Create a node and a few revisions.
$node = $this->drupalCreateNode(['langcode' => 'en']);
$initial_revision_id = $node->getRevisionId();
$initial_title = $node->label();
$this->createRevisions($node, 2);
// Translate the node and create a few translation revisions.
$translation = $node->addTranslation('it');
$this->createRevisions($translation, 3);
$revert_id = $node->getRevisionId();
$translated_title = $translation->label();
$untranslatable_string = $node->untranslatable_string_field->value;
// Create a new revision for the default translation in-between a series of
// translation revisions.
$this->createRevisions($node, 1);
$default_translation_title = $node->label();
// And create a few more translation revisions.
$this->createRevisions($translation, 2);
$translation_revision_id = $translation->getRevisionId();
// Now revert the a translation revision preceding the last default
// translation revision, and check that the desired value was reverted but
// the default translation value was preserved.
$revert_translation_url = Url::fromRoute('node.revision_revert_translation_confirm', [
'node' => $node->id(),
'node_revision' => $revert_id,
'langcode' => 'it',
]);
$this->drupalPostForm($revert_translation_url, [], t('Revert'));
/** @var \Drupal\node\NodeStorage $node_storage */
$node_storage = $this->container->get('entity.manager')->getStorage('node');
$node_storage->resetCache();
/** @var \Drupal\node\NodeInterface $node */
$node = $node_storage->load($node->id());
$this->assertTrue($node->getRevisionId() > $translation_revision_id);
$this->assertEqual($node->label(), $default_translation_title);
$this->assertEqual($node->getTranslation('it')->label(), $translated_title);
$this->assertNotEqual($node->untranslatable_string_field->value, $untranslatable_string);
$latest_revision_id = $translation->getRevisionId();
// Now revert the a translation revision preceding the last default
// translation revision again, and check that the desired value was reverted
// but the default translation value was preserved. But in addition the
// untranslated field will be reverted as well.
$this->drupalPostForm($revert_translation_url, ['revert_untranslated_fields' => TRUE], t('Revert'));
$node_storage->resetCache();
/** @var \Drupal\node\NodeInterface $node */
$node = $node_storage->load($node->id());
$this->assertTrue($node->getRevisionId() > $latest_revision_id);
$this->assertEqual($node->label(), $default_translation_title);
$this->assertEqual($node->getTranslation('it')->label(), $translated_title);
$this->assertEqual($node->untranslatable_string_field->value, $untranslatable_string);
$latest_revision_id = $translation->getRevisionId();
// Now revert the entity revision to the initial one where the translation
// didn't exist.
$revert_url = Url::fromRoute('node.revision_revert_confirm', [
'node' => $node->id(),
'node_revision' => $initial_revision_id,
]);
$this->drupalPostForm($revert_url, [], t('Revert'));
$node_storage->resetCache();
/** @var \Drupal\node\NodeInterface $node */
$node = $node_storage->load($node->id());
$this->assertTrue($node->getRevisionId() > $latest_revision_id);
$this->assertEqual($node->label(), $initial_title);
$this->assertFalse($node->hasTranslation('it'));
}
/**
* Creates a series of revisions for the specified node.
*
* @param \Drupal\node\NodeInterface $node
* The node object.
* @param $count
* The number of revisions to be created.
*/
protected function createRevisions(NodeInterface $node, $count) {
for ($i = 0; $i < $count; $i++) {
$node->title = $this->randomString();
$node->untranslatable_string_field->value = $this->randomString();
$node->setNewRevision(TRUE);
$node->save();
}
}
}
@@ -0,0 +1,259 @@
<?php
namespace Drupal\node\Tests;
use Drupal\field\Entity\FieldConfig;
use Drupal\node\Entity\NodeType;
use Drupal\Core\Url;
use Drupal\system\Tests\Menu\AssertBreadcrumbTrait;
/**
* Ensures that node type functions work correctly.
*
* @group node
*/
class NodeTypeTest extends NodeTestBase {
use AssertBreadcrumbTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['field_ui', 'block'];
/**
* Ensures that node type functions (node_type_get_*) work correctly.
*
* Load available node types and validate the returned data.
*/
public function testNodeTypeGetFunctions() {
$node_types = NodeType::loadMultiple();
$node_names = node_type_get_names();
$this->assertTrue(isset($node_types['article']), 'Node type article is available.');
$this->assertTrue(isset($node_types['page']), 'Node type basic page is available.');
$this->assertEqual($node_types['article']->label(), $node_names['article'], 'Correct node type base has been returned.');
$article = NodeType::load('article');
$this->assertEqual($node_types['article'], $article, 'Correct node type has been returned.');
$this->assertEqual($node_types['article']->label(), $article->label(), 'Correct node type name has been returned.');
}
/**
* Tests creating a content type programmatically and via a form.
*/
public function testNodeTypeCreation() {
// Create a content type programmatically.
$type = $this->drupalCreateContentType();
$type_exists = (bool) NodeType::load($type->id());
$this->assertTrue($type_exists, 'The new content type has been created in the database.');
// Log in a test user.
$web_user = $this->drupalCreateUser(['create ' . $type->label() . ' content']);
$this->drupalLogin($web_user);
$this->drupalGet('node/add/' . $type->id());
$this->assertResponse(200, 'The new content type can be accessed at node/add.');
// Create a content type via the user interface.
$web_user = $this->drupalCreateUser(['bypass node access', 'administer content types']);
$this->drupalLogin($web_user);
$this->drupalGet('node/add');
$this->assertCacheTag('config:node_type_list');
$this->assertCacheContext('user.permissions');
$elements = $this->cssSelect('dl.node-type-list dt');
$this->assertEqual(3, count($elements));
$edit = [
'name' => 'foo',
'title_label' => 'title for foo',
'type' => 'foo',
];
$this->drupalPostForm('admin/structure/types/add', $edit, t('Save and manage fields'));
$type_exists = (bool) NodeType::load('foo');
$this->assertTrue($type_exists, 'The new content type has been created in the database.');
$this->drupalGet('node/add');
$elements = $this->cssSelect('dl.node-type-list dt');
$this->assertEqual(4, count($elements));
}
/**
* Tests editing a node type using the UI.
*/
public function testNodeTypeEditing() {
$this->drupalPlaceBlock('system_breadcrumb_block');
$web_user = $this->drupalCreateUser(['bypass node access', 'administer content types', 'administer node fields']);
$this->drupalLogin($web_user);
$field = FieldConfig::loadByName('node', 'page', 'body');
$this->assertEqual($field->getLabel(), 'Body', 'Body field was found.');
// Verify that title and body fields are displayed.
$this->drupalGet('node/add/page');
$this->assertRaw('Title', 'Title field was found.');
$this->assertRaw('Body', 'Body field was found.');
// Rename the title field.
$edit = [
'title_label' => 'Foo',
];
$this->drupalPostForm('admin/structure/types/manage/page', $edit, t('Save content type'));
$this->drupalGet('node/add/page');
$this->assertRaw('Foo', 'New title label was displayed.');
$this->assertNoRaw('Title', 'Old title label was not displayed.');
// Change the name and the description.
$edit = [
'name' => 'Bar',
'description' => 'Lorem ipsum.',
];
$this->drupalPostForm('admin/structure/types/manage/page', $edit, t('Save content type'));
$this->drupalGet('node/add');
$this->assertRaw('Bar', 'New name was displayed.');
$this->assertRaw('Lorem ipsum', 'New description was displayed.');
$this->clickLink('Bar');
$this->assertRaw('Foo', 'Title field was found.');
$this->assertRaw('Body', 'Body field was found.');
// Change the name through the API
/** @var \Drupal\node\NodeTypeInterface $node_type */
$node_type = NodeType::load('page');
$node_type->set('name', 'NewBar');
$node_type->save();
/** @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_info */
$bundle_info = \Drupal::service('entity_type.bundle.info');
$node_bundles = $bundle_info->getBundleInfo('node');
$this->assertEqual($node_bundles['page']['label'], 'NewBar', 'Node type bundle cache is updated');
// Remove the body field.
$this->drupalPostForm('admin/structure/types/manage/page/fields/node.page.body/delete', [], t('Delete'));
// Resave the settings for this type.
$this->drupalPostForm('admin/structure/types/manage/page', [], t('Save content type'));
$front_page_path = Url::fromRoute('<front>')->toString();
$this->assertBreadcrumb('admin/structure/types/manage/page/fields', [
$front_page_path => 'Home',
'admin/structure/types' => 'Content types',
'admin/structure/types/manage/page' => 'NewBar',
]);
// Check that the body field doesn't exist.
$this->drupalGet('node/add/page');
$this->assertNoRaw('Body', 'Body field was not found.');
}
/**
* Tests deleting a content type that still has content.
*/
public function testNodeTypeDeletion() {
$this->drupalPlaceBlock('page_title_block');
// Create a content type programmatically.
$type = $this->drupalCreateContentType();
// Log in a test user.
$web_user = $this->drupalCreateUser([
'bypass node access',
'administer content types',
]);
$this->drupalLogin($web_user);
// Add a new node of this type.
$node = $this->drupalCreateNode(['type' => $type->id()]);
// Attempt to delete the content type, which should not be allowed.
$this->drupalGet('admin/structure/types/manage/' . $type->label() . '/delete');
$this->assertRaw(
t('%type is used by 1 piece of content on your site. You can not remove this content type until you have removed all of the %type content.', ['%type' => $type->label()]),
'The content type will not be deleted until all nodes of that type are removed.'
);
$this->assertNoText(t('This action cannot be undone.'), 'The node type deletion confirmation form is not available.');
// Delete the node.
$node->delete();
// Attempt to delete the content type, which should now be allowed.
$this->drupalGet('admin/structure/types/manage/' . $type->label() . '/delete');
$this->assertRaw(
t('Are you sure you want to delete the content type %type?', ['%type' => $type->label()]),
'The content type is available for deletion.'
);
$this->assertText(t('This action cannot be undone.'), 'The node type deletion confirmation form is available.');
// Test that a locked node type could not be deleted.
$this->container->get('module_installer')->install(['node_test_config']);
// Lock the default node type.
$locked = \Drupal::state()->get('node.type.locked');
$locked['default'] = 'default';
\Drupal::state()->set('node.type.locked', $locked);
// Call to flush all caches after installing the forum module in the same
// way installing a module through the UI does.
$this->resetAll();
$this->drupalGet('admin/structure/types/manage/default');
$this->assertNoLink(t('Delete'));
$this->drupalGet('admin/structure/types/manage/default/delete');
$this->assertResponse(403);
$this->container->get('module_installer')->uninstall(['node_test_config']);
$this->container = \Drupal::getContainer();
unset($locked['default']);
\Drupal::state()->set('node.type.locked', $locked);
$this->drupalGet('admin/structure/types/manage/default');
$this->clickLink(t('Delete'));
$this->assertResponse(200);
$this->drupalPostForm(NULL, [], t('Delete'));
$this->assertFalse((bool) NodeType::load('default'), 'Node type with machine default deleted.');
}
/**
* Tests Field UI integration for content types.
*/
public function testNodeTypeFieldUiPermissions() {
// Create an admin user who can only manage node fields.
$admin_user_1 = $this->drupalCreateUser(['administer content types', 'administer node fields']);
$this->drupalLogin($admin_user_1);
// Test that the user only sees the actions available to him.
$this->drupalGet('admin/structure/types');
$this->assertLinkByHref('admin/structure/types/manage/article/fields');
$this->assertNoLinkByHref('admin/structure/types/manage/article/display');
// Create another admin user who can manage node fields display.
$admin_user_2 = $this->drupalCreateUser(['administer content types', 'administer node display']);
$this->drupalLogin($admin_user_2);
// Test that the user only sees the actions available to him.
$this->drupalGet('admin/structure/types');
$this->assertNoLinkByHref('admin/structure/types/manage/article/fields');
$this->assertLinkByHref('admin/structure/types/manage/article/display');
}
/**
* Tests for when there are no content types defined.
*/
public function testNodeTypeNoContentType() {
/** @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface $bundle_info */
$bundle_info = \Drupal::service('entity_type.bundle.info');
$this->assertEqual(2, count($bundle_info->getBundleInfo('node')), 'The bundle information service has 2 bundles for the Node entity type.');
$web_user = $this->drupalCreateUser(['administer content types']);
$this->drupalLogin($web_user);
// Delete 'article' bundle.
$this->drupalPostForm('admin/structure/types/manage/article/delete', [], t('Delete'));
// Delete 'page' bundle.
$this->drupalPostForm('admin/structure/types/manage/page/delete', [], t('Delete'));
// Navigate to content type administration screen
$this->drupalGet('admin/structure/types');
$this->assertRaw(t('No content types available. <a href=":link">Add content type</a>.', [
':link' => Url::fromRoute('node.type_add')->toString(),
]), 'Empty text when there are no content types in the system is correct.');
$bundle_info->clearCachedBundles();
$this->assertEqual(0, count($bundle_info->getBundleInfo('node')), 'The bundle information service has 0 bundles for the Node entity type.');
}
}
@@ -0,0 +1,475 @@
<?php
namespace Drupal\node\Tests;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\node\Entity\NodeType;
use Drupal\taxonomy\Entity\Term;
use Drupal\taxonomy\Entity\Vocabulary;
/**
* Tests the node entity preview functionality.
*
* @group node
*/
class PagePreviewTest extends NodeTestBase {
use EntityReferenceTestTrait;
use CommentTestTrait;
/**
* Enable the comment, node and taxonomy modules to test on the preview.
*
* @var array
*/
public static $modules = ['node', 'taxonomy', 'comment', 'image', 'file', 'text', 'node_test', 'menu_ui'];
/**
* The name of the created field.
*
* @var string
*/
protected $fieldName;
protected function setUp() {
parent::setUp();
$this->addDefaultCommentField('node', 'page');
$web_user = $this->drupalCreateUser(['edit own page content', 'create page content', 'administer menu']);
$this->drupalLogin($web_user);
// Add a vocabulary so we can test different view modes.
$vocabulary = Vocabulary::create([
'name' => $this->randomMachineName(),
'description' => $this->randomMachineName(),
'vid' => $this->randomMachineName(),
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
'help' => '',
]);
$vocabulary->save();
$this->vocabulary = $vocabulary;
// Add a term to the vocabulary.
$term = Term::create([
'name' => $this->randomMachineName(),
'description' => $this->randomMachineName(),
'vid' => $this->vocabulary->id(),
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
]);
$term->save();
$this->term = $term;
// Create an image field.
FieldStorageConfig::create([
'field_name' => 'field_image',
'entity_type' => 'node',
'type' => 'image',
'settings' => [],
'cardinality' => FieldStorageConfig::CARDINALITY_UNLIMITED,
])->save();
$field_config = FieldConfig::create([
'field_name' => 'field_image',
'label' => 'Images',
'entity_type' => 'node',
'bundle' => 'page',
'required' => FALSE,
'settings' => [],
]);
$field_config->save();
// Create a field.
$this->fieldName = mb_strtolower($this->randomMachineName());
$handler_settings = [
'target_bundles' => [
$this->vocabulary->id() => $this->vocabulary->id(),
],
'auto_create' => TRUE,
];
$this->createEntityReferenceField('node', 'page', $this->fieldName, 'Tags', 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
entity_get_form_display('node', 'page', 'default')
->setComponent($this->fieldName, [
'type' => 'entity_reference_autocomplete_tags',
])
->save();
// Show on default display and teaser.
entity_get_display('node', 'page', 'default')
->setComponent($this->fieldName, [
'type' => 'entity_reference_label',
])
->save();
entity_get_display('node', 'page', 'teaser')
->setComponent($this->fieldName, [
'type' => 'entity_reference_label',
])
->save();
entity_get_form_display('node', 'page', 'default')
->setComponent('field_image', [
'type' => 'image_image',
'settings' => [],
])
->save();
entity_get_display('node', 'page', 'default')
->setComponent('field_image')
->save();
// Create a multi-value text field.
$field_storage = FieldStorageConfig::create([
'field_name' => 'field_test_multi',
'entity_type' => 'node',
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
'type' => 'text',
'settings' => [
'max_length' => 50,
],
]);
$field_storage->save();
FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => 'page',
])->save();
entity_get_form_display('node', 'page', 'default')
->setComponent('field_test_multi', [
'type' => 'text_textfield',
])
->save();
entity_get_display('node', 'page', 'default')
->setComponent('field_test_multi', [
'type' => 'string',
])
->save();
}
/**
* Checks the node preview functionality.
*/
public function testPagePreview() {
$title_key = 'title[0][value]';
$body_key = 'body[0][value]';
$term_key = $this->fieldName . '[target_id]';
// Fill in node creation form and preview node.
$edit = [];
$edit[$title_key] = '<em>' . $this->randomMachineName(8) . '</em>';
$edit[$body_key] = $this->randomMachineName(16);
$edit[$term_key] = $this->term->getName();
// Upload an image.
$test_image = current($this->drupalGetTestFiles('image', 39325));
$edit['files[field_image_0][]'] = \Drupal::service('file_system')->realpath($test_image->uri);
$this->drupalPostForm('node/add/page', $edit, t('Upload'));
// Add an alt tag and preview the node.
$this->drupalPostForm(NULL, ['field_image[0][alt]' => 'Picture of llamas'], t('Preview'));
// Check that the preview is displaying the title, body and term.
$this->assertTitle(t('@title | Drupal', ['@title' => $edit[$title_key]]), 'Basic page title is preview.');
$this->assertEscaped($edit[$title_key], 'Title displayed and escaped.');
$this->assertText($edit[$body_key], 'Body displayed.');
$this->assertText($edit[$term_key], 'Term displayed.');
$this->assertLink(t('Back to content editing'));
// Check that we see the class of the node type on the body element.
$body_class_element = $this->xpath("//body[contains(@class, 'page-node-type-page')]");
$this->assertTrue(!empty($body_class_element), 'Node type body class found.');
// Get the UUID.
$url = parse_url($this->getUrl());
$paths = explode('/', $url['path']);
$view_mode = array_pop($paths);
$uuid = array_pop($paths);
// Switch view mode. We'll remove the body from the teaser view mode.
entity_get_display('node', 'page', 'teaser')
->removeComponent('body')
->save();
$view_mode_edit = ['view_mode' => 'teaser'];
$this->drupalPostForm('node/preview/' . $uuid . '/full', $view_mode_edit, t('Switch'));
$this->assertRaw('view-mode-teaser', 'View mode teaser class found.');
$this->assertNoText($edit[$body_key], 'Body not displayed.');
// Check that the title, body and term fields are displayed with the
// values after going back to the content edit page.
$this->clickLink(t('Back to content editing'));
$this->assertFieldByName($title_key, $edit[$title_key], 'Title field displayed.');
$this->assertFieldByName($body_key, $edit[$body_key], 'Body field displayed.');
$this->assertFieldByName($term_key, $edit[$term_key], 'Term field displayed.');
$this->assertFieldByName('field_image[0][alt]', 'Picture of llamas');
$this->drupalPostAjaxForm(NULL, [], ['field_test_multi_add_more' => t('Add another item')], NULL, [], [], 'node-page-form');
$this->assertFieldByName('field_test_multi[0][value]');
$this->assertFieldByName('field_test_multi[1][value]');
// Return to page preview to check everything is as expected.
$this->drupalPostForm(NULL, [], t('Preview'));
$this->assertTitle(t('@title | Drupal', ['@title' => $edit[$title_key]]), 'Basic page title is preview.');
$this->assertEscaped($edit[$title_key], 'Title displayed and escaped.');
$this->assertText($edit[$body_key], 'Body displayed.');
$this->assertText($edit[$term_key], 'Term displayed.');
$this->assertLink(t('Back to content editing'));
// Assert the content is kept when reloading the page.
$this->drupalGet('node/add/page', ['query' => ['uuid' => $uuid]]);
$this->assertFieldByName($title_key, $edit[$title_key], 'Title field displayed.');
$this->assertFieldByName($body_key, $edit[$body_key], 'Body field displayed.');
$this->assertFieldByName($term_key, $edit[$term_key], 'Term field displayed.');
// Save the node - this is a new POST, so we need to upload the image.
$this->drupalPostForm('node/add/page', $edit, t('Upload'));
$this->drupalPostForm(NULL, ['field_image[0][alt]' => 'Picture of llamas'], t('Save'));
$node = $this->drupalGetNodeByTitle($edit[$title_key]);
// Check the term was displayed on the saved node.
$this->drupalGet('node/' . $node->id());
$this->assertText($edit[$term_key], 'Term displayed.');
// Check the term appears again on the edit form.
$this->drupalGet('node/' . $node->id() . '/edit');
$this->assertFieldByName($term_key, $edit[$term_key] . ' (' . $this->term->id() . ')', 'Term field displayed.');
// Check with two new terms on the edit form, additionally to the existing
// one.
$edit = [];
$newterm1 = $this->randomMachineName(8);
$newterm2 = $this->randomMachineName(8);
$edit[$term_key] = $this->term->getName() . ', ' . $newterm1 . ', ' . $newterm2;
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Preview'));
$this->assertRaw('>' . $newterm1 . '<', 'First new term displayed.');
$this->assertRaw('>' . $newterm2 . '<', 'Second new term displayed.');
// The first term should be displayed as link, the others not.
$this->assertLink($this->term->getName());
$this->assertNoLink($newterm1);
$this->assertNoLink($newterm2);
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
// Check with one more new term, keeping old terms, removing the existing
// one.
$edit = [];
$newterm3 = $this->randomMachineName(8);
$edit[$term_key] = $newterm1 . ', ' . $newterm3 . ', ' . $newterm2;
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Preview'));
$this->assertRaw('>' . $newterm1 . '<', 'First existing term displayed.');
$this->assertRaw('>' . $newterm2 . '<', 'Second existing term displayed.');
$this->assertRaw('>' . $newterm3 . '<', 'Third new term displayed.');
$this->assertNoText($this->term->getName());
$this->assertLink($newterm1);
$this->assertLink($newterm2);
$this->assertNoLink($newterm3);
// Check that editing an existing node after it has been previewed and not
// saved doesn't remember the previous changes.
$edit = [
$title_key => $this->randomMachineName(8),
];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Preview'));
$this->assertText($edit[$title_key], 'New title displayed.');
$this->clickLink(t('Back to content editing'));
$this->assertFieldByName($title_key, $edit[$title_key], 'New title value displayed.');
// Navigate away from the node without saving.
$this->drupalGet('<front>');
// Go back to the edit form, the title should have its initial value.
$this->drupalGet('node/' . $node->id() . '/edit');
$this->assertFieldByName($title_key, $node->label(), 'Correct title value displayed.');
// Check with required preview.
$node_type = NodeType::load('page');
$node_type->setPreviewMode(DRUPAL_REQUIRED);
$node_type->save();
$this->drupalGet('node/add/page');
$this->assertNoRaw('edit-submit');
$this->drupalPostForm('node/add/page', [$title_key => 'Preview'], t('Preview'));
$this->clickLink(t('Back to content editing'));
$this->assertRaw('edit-submit');
// Check that destination is remembered when clicking on preview. When going
// back to the edit form and clicking save, we should go back to the
// original destination, if set.
$destination = 'node';
$this->drupalPostForm($node->toUrl('edit-form'), [], t('Preview'), ['query' => ['destination' => $destination]]);
$parameters = ['node_preview' => $node->uuid(), 'view_mode_id' => 'full'];
$options = ['absolute' => TRUE, 'query' => ['destination' => $destination]];
$this->assertUrl(Url::fromRoute('entity.node.preview', $parameters, $options));
$this->drupalPostForm(NULL, ['view_mode' => 'teaser'], t('Switch'));
$this->clickLink(t('Back to content editing'));
$this->drupalPostForm(NULL, [], t('Save'));
$this->assertUrl($destination);
// Check that preview page works as expected without a destination set.
$this->drupalPostForm($node->toUrl('edit-form'), [], t('Preview'));
$parameters = ['node_preview' => $node->uuid(), 'view_mode_id' => 'full'];
$this->assertUrl(Url::fromRoute('entity.node.preview', $parameters, ['absolute' => TRUE]));
$this->drupalPostForm(NULL, ['view_mode' => 'teaser'], t('Switch'));
$this->clickLink(t('Back to content editing'));
$this->drupalPostForm(NULL, [], t('Save'));
$this->assertUrl($node->toUrl());
$this->assertResponse(200);
/** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
// Assert multiple items can be added and are not lost when previewing.
$test_image_1 = current($this->drupalGetTestFiles('image', 39325));
$edit_image_1['files[field_image_0][]'] = $file_system->realpath($test_image_1->uri);
$test_image_2 = current($this->drupalGetTestFiles('image', 39325));
$edit_image_2['files[field_image_1][]'] = $file_system->realpath($test_image_2->uri);
$edit['field_image[0][alt]'] = 'Alt 1';
$this->drupalPostForm('node/add/page', $edit_image_1, t('Upload'));
$this->drupalPostForm(NULL, $edit, t('Preview'));
$this->clickLink(t('Back to content editing'));
$this->assertFieldByName('files[field_image_1][]');
$this->drupalPostForm(NULL, $edit_image_2, t('Upload'));
$this->assertNoFieldByName('files[field_image_1][]');
$title = 'node_test_title';
$example_text_1 = 'example_text_preview_1';
$example_text_2 = 'example_text_preview_2';
$example_text_3 = 'example_text_preview_3';
$this->drupalGet('node/add/page');
$edit = [
'title[0][value]' => $title,
'field_test_multi[0][value]' => $example_text_1,
];
$this->assertRaw('Storage is not set');
$this->drupalPostForm(NULL, $edit, t('Preview'));
$this->clickLink(t('Back to content editing'));
$this->assertRaw('Storage is set');
$this->assertFieldByName('field_test_multi[0][value]');
$this->drupalPostForm(NULL, [], t('Save'));
$this->assertText('Basic page ' . $title . ' has been created.');
$node = $this->drupalGetNodeByTitle($title);
$this->drupalGet('node/' . $node->id() . '/edit');
$this->drupalPostAjaxForm(NULL, [], ['field_test_multi_add_more' => t('Add another item')]);
$this->drupalPostAjaxForm(NULL, [], ['field_test_multi_add_more' => t('Add another item')]);
$edit = [
'field_test_multi[1][value]' => $example_text_2,
'field_test_multi[2][value]' => $example_text_3,
];
$this->drupalPostForm(NULL, $edit, t('Preview'));
$this->clickLink(t('Back to content editing'));
$this->drupalPostForm(NULL, $edit, t('Preview'));
$this->clickLink(t('Back to content editing'));
$this->assertFieldByName('field_test_multi[0][value]', $example_text_1);
$this->assertFieldByName('field_test_multi[1][value]', $example_text_2);
$this->assertFieldByName('field_test_multi[2][value]', $example_text_3);
// Now save the node and make sure all values got saved.
$this->drupalPostForm(NULL, [], t('Save'));
$this->assertText($example_text_1);
$this->assertText($example_text_2);
$this->assertText($example_text_3);
// Edit again, change the menu_ui settings and click on preview.
$this->drupalGet('node/' . $node->id() . '/edit');
$edit = [
'menu[enabled]' => TRUE,
'menu[title]' => 'Changed title',
];
$this->drupalPostForm(NULL, $edit, t('Preview'));
$this->clickLink(t('Back to content editing'));
$this->assertFieldChecked('edit-menu-enabled', 'Menu option is still checked');
$this->assertFieldByName('menu[title]', 'Changed title', 'Menu link title is correct after preview');
// Save, change the title while saving and make sure that it is correctly
// saved.
$edit = [
'menu[enabled]' => TRUE,
'menu[title]' => 'Second title change',
];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->drupalGet('node/' . $node->id() . '/edit');
$this->assertFieldByName('menu[title]', 'Second title change', 'Menu link title is correct after saving');
}
/**
* Checks the node preview functionality, when using revisions.
*/
public function testPagePreviewWithRevisions() {
$title_key = 'title[0][value]';
$body_key = 'body[0][value]';
$term_key = $this->fieldName . '[target_id]';
// Force revision on "Basic page" content.
$node_type = NodeType::load('page');
$node_type->setNewRevision(TRUE);
$node_type->save();
// Fill in node creation form and preview node.
$edit = [];
$edit[$title_key] = $this->randomMachineName(8);
$edit[$body_key] = $this->randomMachineName(16);
$edit[$term_key] = $this->term->id();
$edit['revision_log[0][value]'] = $this->randomString(32);
$this->drupalPostForm('node/add/page', $edit, t('Preview'));
// Check that the preview is displaying the title, body and term.
$this->assertTitle(t('@title | Drupal', ['@title' => $edit[$title_key]]), 'Basic page title is preview.');
$this->assertText($edit[$title_key], 'Title displayed.');
$this->assertText($edit[$body_key], 'Body displayed.');
$this->assertText($edit[$term_key], 'Term displayed.');
// Check that the title and body fields are displayed with the correct
// values after going back to the content edit page.
$this->clickLink(t('Back to content editing')); $this->assertFieldByName($title_key, $edit[$title_key], 'Title field displayed.');
$this->assertFieldByName($body_key, $edit[$body_key], 'Body field displayed.');
$this->assertFieldByName($term_key, $edit[$term_key], 'Term field displayed.');
// Check that the revision log field has the correct value.
$this->assertFieldByName('revision_log[0][value]', $edit['revision_log[0][value]'], 'Revision log field displayed.');
// Save the node after coming back from the preview page so we can create a
// pending revision for it.
$this->drupalPostForm(NULL, [], t('Save'));
$node = $this->drupalGetNodeByTitle($edit[$title_key]);
// Check that previewing a pending revision of a node works. This can not be
// accomplished through the UI so we have to use API calls.
// @todo Change this test to use the UI when we will be able to create
// pending revisions in core.
// @see https://www.drupal.org/node/2725533
$node->setNewRevision(TRUE);
$node->isDefaultRevision(FALSE);
/** @var \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver */
$controller_resolver = \Drupal::service('controller_resolver');
$node_preview_controller = $controller_resolver->getControllerFromDefinition('\Drupal\node\Controller\NodePreviewController::view');
$node_preview_controller($node, 'full');
}
/**
* Checks the node preview accessible for simultaneous node editing.
*/
public function testSimultaneousPreview() {
$title_key = 'title[0][value]';
$node = $this->drupalCreateNode([]);
$edit = [$title_key => 'New page title'];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Preview'));
$this->assertText($edit[$title_key]);
$user2 = $this->drupalCreateUser(['edit any page content']);
$this->drupalLogin($user2);
$this->drupalGet('node/' . $node->id() . '/edit');
$this->assertFieldByName($title_key, $node->label(), 'No title leaked from previous user.');
$edit2 = [$title_key => 'Another page title'];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit2, t('Preview'));
$this->assertUrl(\Drupal::url('entity.node.preview', ['node_preview' => $node->uuid(), 'view_mode_id' => 'full'], ['absolute' => TRUE]));
$this->assertText($edit2[$title_key]);
}
}
@@ -0,0 +1,118 @@
<?php
namespace Drupal\node\Tests\Views;
use Drupal\Component\Serialization\Json;
use Drupal\user\Entity\User;
/**
* Tests views contextual links on nodes.
*
* @group node
*/
class NodeContextualLinksTest extends NodeTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['contextual'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_contextual_links'];
/**
* Tests contextual links.
*/
public function testNodeContextualLinks() {
$this->drupalCreateContentType(['type' => 'page']);
$this->drupalCreateNode(['promote' => 1]);
$this->drupalGet('node');
$user = $this->drupalCreateUser(['administer nodes', 'access contextual links']);
$this->drupalLogin($user);
$response = $this->renderContextualLinks(['node:node=1:'], 'node');
$this->assertResponse(200);
$json = Json::decode($response);
$this->setRawContent($json['node:node=1:']);
// @todo Add these back when the functionality for making Views displays
// appear in contextual links is working again.
// $this->assertLinkByHref('node/1/contextual-links', 0, 'The contextual link to the view was found.');
// $this->assertLink('Test contextual link', 0, 'The contextual link to the view was found.');
}
/**
* Get server-rendered contextual links for the given contextual link ids.
*
* Copied from \Drupal\contextual\Tests\ContextualDynamicContextTest::renderContextualLinks().
*
* @param array $ids
* An array of contextual link ids.
* @param string $current_path
* The Drupal path for the page for which the contextual links are rendered.
*
* @return string
* The response body.
*/
protected function renderContextualLinks($ids, $current_path) {
// Build POST values.
$post = [];
for ($i = 0; $i < count($ids); $i++) {
$post['ids[' . $i . ']'] = $ids[$i];
}
// Serialize POST values.
foreach ($post as $key => $value) {
// Encode according to application/x-www-form-urlencoded
// Both names and values needs to be urlencoded, according to
// http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
$post[$key] = urlencode($key) . '=' . urlencode($value);
}
$post = implode('&', $post);
// Perform HTTP request.
return $this->curlExec([
CURLOPT_URL => \Drupal::url('contextual.render', [], ['absolute' => TRUE, 'query' => ['destination' => $current_path]]),
CURLOPT_POST => TRUE,
CURLOPT_POSTFIELDS => $post,
CURLOPT_HTTPHEADER => [
'Accept: application/json',
'Content-Type: application/x-www-form-urlencoded',
],
]);
}
/**
* Tests if the node page works if Contextual Links is disabled.
*
* All views have Contextual links enabled by default, even with the
* Contextual links module disabled. This tests if no calls are done to the
* Contextual links module by views when it is disabled.
*
* @see https://www.drupal.org/node/2379811
*/
public function testPageWithDisabledContextualModule() {
\Drupal::service('module_installer')->uninstall(['contextual']);
\Drupal::service('module_installer')->install(['views_ui']);
// Ensure that contextual links don't get called for admin users.
$admin_user = User::load(1);
$admin_user->setPassword('new_password');
$admin_user->pass_raw = 'new_password';
$admin_user->save();
$this->drupalCreateContentType(['type' => 'page']);
$this->drupalCreateNode(['promote' => 1]);
$this->drupalLogin($admin_user);
$this->drupalGet('node');
}
}