Update Composer, update everything

This commit is contained in:
Oliver Davies 2018-11-23 12:29:20 +00:00
parent ea3e94409f
commit dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions

View file

@ -152,6 +152,12 @@ function node_access_test_node_access(NodeInterface $node, $op, AccountInterface
// Make all Catalan content secret.
return AccessResult::forbidden()->setCacheMaxAge(0);
}
// Grant access if a specific user is specified.
if (\Drupal::state()->get('node_access_test.allow_uid') === $account->id()) {
return AccessResult::allowed();
}
// No opinion.
return AccessResult::neutral()->setCacheMaxAge(0);
}

View file

@ -5,4 +5,4 @@ package: Testing
version: VERSION
core: 8.x
dependencies:
- options
- drupal:options

View file

@ -14,7 +14,6 @@ use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\node\NodeInterface;
/**
* Implements hook_ENTITY_TYPE_view() for node entities.
*/
@ -156,7 +155,7 @@ function node_test_node_update(NodeInterface $node) {
*/
function node_test_entity_view_mode_alter(&$view_mode, EntityInterface $entity, $context) {
// Only alter the view mode if we are on the test callback.
$change_view_mode = \Drupal::state()->get( 'node_test_change_view_mode') ?: '';
$change_view_mode = \Drupal::state()->get('node_test_change_view_mode') ?: '';
if ($change_view_mode) {
$view_mode = $change_view_mode;
}
@ -183,10 +182,10 @@ function node_test_node_insert(NodeInterface $node) {
*/
function node_test_form_alter(&$form, FormStateInterface $form_state, $form_id) {
if (!$form_state->get('node_test_form_alter')) {
drupal_set_message('Storage is not set');
\Drupal::messenger()->addStatus('Storage is not set');
$form_state->set('node_test_form_alter', TRUE);
}
else {
drupal_set_message('Storage is set');
\Drupal::messenger()->addStatus('Storage is set');
}
}

View file

@ -5,6 +5,6 @@ package: Testing
version: VERSION
core: 8.x
dependencies:
- node
- views
- language
- drupal:node
- drupal:views
- drupal:language

View file

@ -202,7 +202,7 @@ display:
hide_empty: false
empty_zero: false
hide_alter_empty: true
text: 'Link to delete revision'
text: 'Link to revert revision'
entity_type: node
plugin_id: node_revision_link_revert
filters: { }

View file

@ -0,0 +1,124 @@
<?php
namespace Drupal\Tests\node\Functional\Hal;
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
use Drupal\Tests\node\Functional\Rest\NodeResourceTestBase;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\user\Entity\User;
/**
* @group hal
*/
class NodeHalJsonAnonTest extends NodeResourceTestBase {
use HalEntityNormalizationTrait;
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected static $patchProtectedFieldNames = [
'revision_timestamp' => NULL,
'created' => "The 'administer nodes' permission is required.",
'changed' => NULL,
'promote' => "The 'administer nodes' permission is required.",
'sticky' => "The 'administer nodes' permission is required.",
'path' => "The following permissions are required: 'create url aliases' OR 'administer url aliases'.",
'revision_uid' => NULL,
];
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
$default_normalization = parent::getExpectedNormalizedEntity();
$normalization = $this->applyHalFieldNormalization($default_normalization);
$author = User::load($this->entity->getOwnerId());
return $normalization + [
'_links' => [
'self' => [
'href' => $this->baseUrl . '/llama?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/node/camelids',
],
$this->baseUrl . '/rest/relation/node/camelids/revision_uid' => [
[
'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json',
],
],
$this->baseUrl . '/rest/relation/node/camelids/uid' => [
[
'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json',
'lang' => 'en',
],
],
],
'_embedded' => [
$this->baseUrl . '/rest/relation/node/camelids/revision_uid' => [
[
'_links' => [
'self' => [
'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/user/user',
],
],
'uuid' => [
['value' => $author->uuid()],
],
],
],
$this->baseUrl . '/rest/relation/node/camelids/uid' => [
[
'_links' => [
'self' => [
'href' => $this->baseUrl . '/user/' . $author->id() . '?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/user/user',
],
],
'uuid' => [
['value' => $author->uuid()],
],
'lang' => 'en',
],
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
return parent::getNormalizedPostEntity() + [
'_links' => [
'type' => [
'href' => $this->baseUrl . '/rest/type/node/camelids',
],
],
];
}
}

View file

@ -0,0 +1,24 @@
<?php
namespace Drupal\Tests\node\Functional\Hal;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group hal
*/
class NodeHalJsonBasicAuthTest extends NodeHalJsonAnonTest {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,19 @@
<?php
namespace Drupal\Tests\node\Functional\Hal;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group hal
*/
class NodeHalJsonCookieTest extends NodeHalJsonAnonTest {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,30 @@
<?php
namespace Drupal\Tests\node\Functional\Hal;
use Drupal\Tests\node\Functional\Rest\NodeTypeResourceTestBase;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* @group hal
*/
class NodeTypeHalJsonAnonTest extends NodeTypeResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
}

View file

@ -0,0 +1,35 @@
<?php
namespace Drupal\Tests\node\Functional\Hal;
use Drupal\Tests\node\Functional\Rest\NodeTypeResourceTestBase;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group hal
*/
class NodeTypeHalJsonBasicAuthTest extends NodeTypeResourceTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal', 'basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,35 @@
<?php
namespace Drupal\Tests\node\Functional\Hal;
use Drupal\Tests\node\Functional\Rest\NodeTypeResourceTestBase;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group hal
*/
class NodeTypeHalJsonCookieTest extends NodeTypeResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -1,6 +1,7 @@
<?php
namespace Drupal\Tests\node\Functional\Migrate\d6;
use Drupal\Tests\node\Kernel\Migrate\d6\MigrateNodeTestBase;
/**
@ -27,10 +28,10 @@ class MigrateNodeRevisionTest extends MigrateNodeTestBase {
* Test node revisions migration from Drupal 6 to 8.
*/
public function testNodeRevision() {
$node = \Drupal::entityManager()->getStorage('node')->loadRevision(2);
$node = \Drupal::entityManager()->getStorage('node')->loadRevision(2001);
/** @var \Drupal\node\NodeInterface $node */
$this->assertIdentical('1', $node->id());
$this->assertIdentical('2', $node->getRevisionId());
$this->assertIdentical('2001', $node->getRevisionId());
$this->assertIdentical('und', $node->langcode->value);
$this->assertIdentical('Test title rev 2', $node->getTitle());
$this->assertIdentical('body test rev 2', $node->body->value);

View file

@ -1,7 +1,7 @@
<?php
namespace Drupal\Tests\node\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
@ -28,7 +28,7 @@ class MultiStepNodeFormBasicOptionsTest extends NodeTestBase {
$this->drupalLogin($web_user);
// Create an unlimited cardinality field.
$this->fieldName = Unicode::strtolower($this->randomMachineName());
$this->fieldName = mb_strtolower($this->randomMachineName());
FieldStorageConfig::create([
'field_name' => $this->fieldName,
'entity_type' => 'node',

View file

@ -3,7 +3,7 @@
namespace Drupal\Tests\node\Functional;
use Drupal\Core\Url;
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
/**
* Tests the node access automatic cacheability bubbling logic.

View file

@ -114,7 +114,7 @@ class NodeAccessBaseTableTest extends NodeTestBase {
$this->drupalPostForm('node/add/article', $edit, t('Save'));
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
$this->assertEqual($is_private, (int)$node->private->value, 'The private status of the node was properly set in the node_access_test table.');
$this->assertEqual($is_private, (int) $node->private->value, 'The private status of the node was properly set in the node_access_test table.');
if ($is_private) {
$private_nodes[] = $node->id();
}

View file

@ -1,7 +1,7 @@
<?php
namespace Drupal\Tests\node\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
@ -50,11 +50,11 @@ class NodeAccessFieldTest extends NodeTestBase {
$this->contentAdminUser = $this->drupalCreateUser(['access content', 'administer content types', 'administer node fields']);
// Add a custom field to the page content type.
$this->fieldName = Unicode::strtolower($this->randomMachineName() . '_field_name');
$this->fieldName = mb_strtolower($this->randomMachineName() . '_field_name');
FieldStorageConfig::create([
'field_name' => $this->fieldName,
'entity_type' => 'node',
'type' => 'text'
'type' => 'text',
])->save();
FieldConfig::create([
'field_name' => $this->fieldName,

View file

@ -34,14 +34,14 @@ class NodeAccessLanguageAwareCombinationTest extends NodeTestBase {
/**
* A normal authenticated user.
*
* @var \Drupal\user\UserInterface.
* @var \Drupal\user\UserInterface
*/
protected $webUser;
/**
* User 1.
*
* @var \Drupal\user\UserInterface.
* @var \Drupal\user\UserInterface
*/
protected $adminUser;

View file

@ -0,0 +1,131 @@
<?php
namespace Drupal\Tests\node\Functional;
use Drupal\language\Entity\ConfigurableLanguage;
/**
* Tests that the node_access system stores the proper fallback marker.
*
* @group node
*/
class NodeAccessLanguageFallbackTest extends NodeTestBase {
/**
* Enable language and a non-language-aware node access module.
*
* @var array
*/
public static $modules = ['language', 'node_access_test', 'content_translation'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// After enabling a node access module, the {node_access} table has to be
// rebuilt.
node_access_rebuild();
// Add Hungarian, Catalan, and Afrikaans.
ConfigurableLanguage::createFromLangcode('hu')->save();
ConfigurableLanguage::createFromLangcode('ca')->save();
ConfigurableLanguage::createFromLangcode('af')->save();
// Enable content translation for the current entity type.
\Drupal::service('content_translation.manager')->setEnabled('node', 'page', TRUE);
}
/**
* Tests node access fallback handling with multiple node languages.
*/
public function testNodeAccessLanguageFallback() {
// The node_access_test module allows nodes to be marked private. We need to
// ensure that system honors the fallback system of node access properly.
// Note that node_access_test_language is language-sensitive and does not
// apply to the fallback test.
// Create one node in Hungarian and marked as private.
$node = $this->drupalCreateNode([
'body' => [[]],
'langcode' => 'hu',
'private' => [['value' => 1]],
'status' => 1,
]);
// There should be one entry in node_access, with fallback set to hu.
$this->checkRecords(1, 'hu');
// Create a translation user.
$admin = $this->drupalCreateUser([
'bypass node access',
'administer nodes',
'translate any entity',
'administer content translation',
]);
$this->drupalLogin($admin);
$this->drupalGet('node/' . $node->id() . '/translations');
$this->assertSession()->statusCodeEquals(200);
// Create a Catalan translation through the UI.
$url_options = ['language' => \Drupal::languageManager()->getLanguage('ca')];
$this->drupalGet('node/' . $node->id() . '/translations/add/hu/ca', $url_options);
$this->assertSession()->statusCodeEquals(200);
// Save the form.
$this->getSession()->getPage()->pressButton('Save (this translation)');
$this->assertSession()->statusCodeEquals(200);
// Check the node access table.
$this->checkRecords(2, 'hu');
// Programmatically create a translation. This process lets us check that
// both forms and code behave in the same way.
$storage = \Drupal::entityTypeManager()->getStorage('node');
// Reload the node.
$node = $storage->load(1);
// Create an Afrikaans translation.
$translation = $node->addTranslation('af');
$translation->title->value = $this->randomString();
$translation->status = 1;
$node->save();
// Check the node access table.
$this->checkRecords(3, 'hu');
// For completeness, edit the Catalan version again.
$this->drupalGet('node/' . $node->id() . '/edit', $url_options);
$this->assertSession()->statusCodeEquals(200);
// Save the form.
$this->getSession()->getPage()->pressButton('Save (this translation)');
$this->assertSession()->statusCodeEquals(200);
// Check the node access table.
$this->checkRecords(3, 'hu');
}
/**
* Queries the node_access table and checks for proper storage.
*
* @param int $count
* The number of rows expected by the query (equal to the translation
* count).
* @param $langcode
* The expected language code set as the fallback property.
*/
public function checkRecords($count, $langcode = 'hu') {
$select = \Drupal::database()
->select('node_access', 'na')
->fields('na', ['nid', 'fallback', 'langcode', 'grant_view'])
->condition('na.realm', 'node_access_test', '=')
->condition('na.gid', 8888, '=');
$records = $select->execute()->fetchAll();
// Check that the expected record count is returned.
$this->assertEquals(count($records), $count);
// The fallback value is 'hu' and should be set to 1. For other languages,
// it should be set to 0. Casting to boolean lets us run that comparison.
foreach ($records as $record) {
$this->assertEquals((bool) $record->fallback, $record->langcode === $langcode);
}
}
}

View file

@ -33,7 +33,7 @@ class NodeAccessMenuLinkTest extends NodeTestBase {
$this->contentAdminUser = $this->drupalCreateUser([
'access content',
'administer content types',
'administer menu'
'administer menu',
]);
$this->config('user.role.' . RoleInterface::ANONYMOUS_ID)->set('permissions', [])->save();

View file

@ -52,7 +52,7 @@ class NodeAccessRebuildNodeGrantsTest extends NodeTestBase {
for ($i = 0; $i < 30; $i++) {
$nodes[] = $this->drupalCreateNode([
'uid' => $this->webUser->id(),
'private' => [['value' => 1]]
'private' => [['value' => 1]],
]);
}

View file

@ -2,7 +2,6 @@
namespace Drupal\Tests\node\Functional;
use Drupal\Component\Utility\Crypt;
use Drupal\Tests\BrowserTestBase;
use Drupal\system\Entity\Action;
@ -30,7 +29,7 @@ class NodeActionsConfigurationTest extends BrowserTestBase {
// Make a POST request to admin/config/system/actions.
$edit = [];
$edit['action'] = Crypt::hashBase64('node_assign_owner_action');
$edit['action'] = 'node_assign_owner_action';
$this->drupalPostForm('admin/config/system/actions', $edit, t('Create'));
$this->assertResponse(200);
@ -40,17 +39,17 @@ class NodeActionsConfigurationTest extends BrowserTestBase {
$edit['label'] = $action_label;
$edit['id'] = strtolower($action_label);
$edit['owner_uid'] = $user->id();
$this->drupalPostForm('admin/config/system/actions/add/' . Crypt::hashBase64('node_assign_owner_action'), $edit, t('Save'));
$this->drupalPostForm('admin/config/system/actions/add/node_assign_owner_action', $edit, t('Save'));
$this->assertResponse(200);
$action_id = $edit['id'];
// Make sure that the new action was saved properly.
$this->assertText(t('The action has been successfully saved.'), 'The node_assign_owner_action action has been successfully saved.');
$this->assertText($action_label, 'The label of the node_assign_owner_action action appears on the actions administration page after saving.');
// Make another POST request to the action edit page.
$this->clickLink(t('Configure'));
preg_match('|admin/config/system/actions/configure/(.+)|', $this->getUrl(), $matches);
$aid = $matches[1];
$edit = [];
$new_action_label = $this->randomMachineName();
$edit['label'] = $new_action_label;
@ -68,7 +67,7 @@ class NodeActionsConfigurationTest extends BrowserTestBase {
$this->clickLink(t('Delete'));
$this->assertResponse(200);
$edit = [];
$this->drupalPostForm("admin/config/system/actions/configure/$aid/delete", $edit, t('Delete'));
$this->drupalPostForm(NULL, $edit, t('Delete'));
$this->assertResponse(200);
// Make sure that the action was actually deleted.
@ -77,7 +76,7 @@ class NodeActionsConfigurationTest extends BrowserTestBase {
$this->assertResponse(200);
$this->assertNoText($new_action_label, 'The label for the node_assign_owner_action action does not appear on the actions administration page after deleting.');
$action = Action::load($aid);
$action = Action::load($action_id);
$this->assertFalse($action, 'The node_assign_owner_action action is not available after being deleted.');
}

View file

@ -4,7 +4,7 @@ namespace Drupal\Tests\node\Functional;
use Drupal\block\Entity\Block;
use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
use Drupal\user\RoleInterface;
/**
@ -141,15 +141,32 @@ class NodeBlockFunctionalTest extends NodeTestBase {
$label = $block->label();
$this->assertNoText($label, 'Block was not displayed on the front page.');
$this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user', 'route']);
// Ensure that a page that does not have a node context can still be cached,
// the front page is the user page which is already cached from the login
// request above.
$this->assertSame('HIT', $this->getSession()->getResponseHeader('X-Drupal-Dynamic-Cache'));
$this->drupalGet('node/add/article');
$this->assertText($label, 'Block was displayed on the node/add/article page.');
$this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'session', 'theme', 'url.path', 'url.query_args', 'user', 'route']);
// The node/add/article page is an admin path and currently uncacheable.
$this->assertSame('UNCACHEABLE', $this->getSession()->getResponseHeader('X-Drupal-Dynamic-Cache'));
$this->drupalGet('node/' . $node1->id());
$this->assertText($label, 'Block was displayed on the node/N when node is of type article.');
$this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user', 'route', 'timezone']);
$this->assertSame('MISS', $this->getSession()->getResponseHeader('X-Drupal-Dynamic-Cache'));
$this->drupalGet('node/' . $node1->id());
$this->assertSame('HIT', $this->getSession()->getResponseHeader('X-Drupal-Dynamic-Cache'));
$this->drupalGet('node/' . $node5->id());
$this->assertNoText($label, 'Block was not displayed on nodes of type page.');
$this->assertCacheContexts(['languages:language_content', 'languages:language_interface', 'theme', 'url.query_args:' . MainContentViewSubscriber::WRAPPER_FORMAT, 'user', 'route', 'timezone']);
$this->assertSame('MISS', $this->getSession()->getResponseHeader('X-Drupal-Dynamic-Cache'));
$this->drupalGet('node/' . $node5->id());
$this->assertSame('HIT', $this->getSession()->getResponseHeader('X-Drupal-Dynamic-Cache'));
$this->drupalLogin($this->adminUser);
$this->drupalGet('admin/structure/block');

View file

@ -5,7 +5,7 @@ namespace Drupal\Tests\node\Functional;
use Drupal\Core\Entity\EntityInterface;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\system\Tests\Entity\EntityWithUriCacheTagsTestBase;
use Drupal\Tests\system\Functional\Entity\EntityWithUriCacheTagsTestBase;
/**
* Tests the Node entity's cache tags.
@ -32,7 +32,7 @@ class NodeCacheTagsTest extends EntityWithUriCacheTagsTestBase {
// Create a "Llama" node.
$node = Node::create(['type' => 'camelids']);
$node->setTitle('Llama')
->setPublished(TRUE)
->setPublished()
->save();
return $node;

View file

@ -0,0 +1,42 @@
<?php
namespace Drupal\Tests\node\Functional;
use Drupal\node\Entity\Node;
/**
* Tests views contextual links on nodes.
*
* @group node
*/
class NodeContextualLinksTest extends NodeTestBase {
/**
* {@inheritdoc}
*/
public static $modules = [
'contextual',
];
/**
* Tests contextual links.
*/
public function testNodeContextualLinks() {
// Create a node item.
$node = Node::create([
'type' => 'article',
'title' => 'Unnamed',
]);
$node->save();
$user = $this->drupalCreateUser([
'administer nodes',
'access contextual links',
]);
$this->drupalLogin($user);
$this->drupalGet('node/' . $node->id());
$this->assertSession()->elementAttributeContains('css', 'div[data-contextual-id]', 'data-contextual-id', 'node:node=' . $node->id() . ':');
}
}

View file

@ -184,7 +184,7 @@ class NodeCreationTest extends NodeTestBase {
$this->assertNoLinkByHref('/admin/structure/types/add');
// Test /node/add page without content types.
foreach (\Drupal::entityManager()->getStorage('node_type')->loadMultiple() as $entity ) {
foreach (\Drupal::entityManager()->getStorage('node_type')->loadMultiple() as $entity) {
$entity->delete();
}

View file

@ -98,7 +98,7 @@ class NodeEditFormTest extends NodeTestBase {
$edit['title[0][value]'] = $this->randomMachineName(8);
$edit[$body_key] = $this->randomMachineName(16);
$edit['revision'] = TRUE;
$this->drupalPostForm(NULL, $edit, t('Save and keep published'));
$this->drupalPostForm(NULL, $edit, t('Save'));
// Ensure that the node revision has been created.
$revised_node = $this->drupalGetNodeByTitle($edit['title[0][value]'], TRUE);
@ -124,12 +124,21 @@ class NodeEditFormTest extends NodeTestBase {
$edit['created[0][value][date]'] = $this->randomMachineName(8);
// Get the current amount of open details elements.
$open_details_elements = count($this->cssSelect('details[open="open"]'));
$this->drupalPostForm(NULL, $edit, t('Save and keep published'));
$this->drupalPostForm(NULL, $edit, t('Save'));
// The node author details must be open.
$this->assertRaw('<details class="node-form-author js-form-wrapper form-wrapper" data-drupal-selector="edit-author" id="edit-author" open="open">');
// Only one extra details element should now be open.
$open_details_elements++;
$this->assertEqual(count($this->cssSelect('details[open="open"]')), $open_details_elements, 'Exactly one extra open &lt;details&gt; element found.');
// Edit the same node, save it and verify it's unpublished after unchecking
// the 'Published' boolean_checkbox and clicking 'Save'.
$this->drupalGet("node/" . $node->id() . "/edit");
$edit = ['status[value]' => FALSE];
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->nodeStorage->resetCache([$node->id()]);
$node = $this->nodeStorage->load($node->id());
$this->assertFalse($node->isPublished(), 'Node is unpublished');
}
/**
@ -143,7 +152,7 @@ class NodeEditFormTest extends NodeTestBase {
$edit = [];
$edit['title[0][value]'] = $this->randomMachineName(8);
$edit[$body_key] = $this->randomMachineName(16);
$this->drupalPostForm('node/add/page', $edit, t('Save and publish'));
$this->drupalPostForm('node/add/page', $edit, t('Save'));
// Check that the node was authored by the currently logged in user.
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
@ -156,7 +165,7 @@ class NodeEditFormTest extends NodeTestBase {
$this->drupalGet('node/' . $node->id() . '/edit');
$this->assertNoFieldByName('uid[0][target_id]');
// Now test with the Autcomplete (Tags) field widget.
// Now test with the Autocomplete (Tags) field widget.
/** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */
$form_display = \Drupal::entityManager()->getStorage('entity_form_display')->load('node.page.default');
$widget = $form_display->getComponent('uid');
@ -172,7 +181,7 @@ class NodeEditFormTest extends NodeTestBase {
$this->drupalLogin($this->adminUser);
// Save the node without making any changes.
$this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save and keep published'));
$this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save'));
$this->nodeStorage->resetCache([$node->id()]);
$node = $this->nodeStorage->load($node->id());
$this->assertIdentical($this->webUser->id(), $node->getOwner()->id());
@ -184,12 +193,49 @@ class NodeEditFormTest extends NodeTestBase {
// Check that saving the node without making any changes keeps the proper
// author ID.
$this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save and keep published'));
$this->drupalPostForm('node/' . $node->id() . '/edit', [], t('Save'));
$this->nodeStorage->resetCache([$node->id()]);
$node = $this->nodeStorage->load($node->id());
$this->assertIdentical($this->webUser->id(), $node->getOwner()->id());
}
/**
* Tests the node meta information.
*/
public function testNodeMetaInformation() {
// Check that regular users (i.e. without the 'administer nodes' permission)
// can not see the meta information.
$this->drupalLogin($this->webUser);
$this->drupalGet('node/add/page');
$this->assertNoText('Not saved yet');
// Create node to edit.
$edit['title[0][value]'] = $this->randomMachineName(8);
$edit['body[0][value]'] = $this->randomMachineName(16);
$this->drupalPostForm(NULL, $edit, t('Save'));
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
$this->drupalGet("node/" . $node->id() . "/edit");
$this->assertNoText('Published');
$this->assertNoText(format_date($node->getChangedTime(), 'short'));
// Check that users with the 'administer nodes' permission can see the meta
// information.
$this->drupalLogin($this->adminUser);
$this->drupalGet('node/add/page');
$this->assertText('Not saved yet');
// Create node to edit.
$edit['title[0][value]'] = $this->randomMachineName(8);
$edit['body[0][value]'] = $this->randomMachineName(16);
$this->drupalPostForm(NULL, $edit, t('Save'));
$node = $this->drupalGetNodeByTitle($edit['title[0][value]']);
$this->drupalGet("node/" . $node->id() . "/edit");
$this->assertText('Published');
$this->assertText(format_date($node->getChangedTime(), 'short'));
}
/**
* Checks that the "authored by" works correctly with various values.
*
@ -203,13 +249,13 @@ class NodeEditFormTest extends NodeTestBase {
$edit = [
$form_element_name => 'invalid-name',
];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published'));
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
$this->assertRaw(t('There are no entities matching "%name".', ['%name' => 'invalid-name']));
// Change the authored by field to an empty string, which should assign
// authorship to the anonymous user (uid 0).
$edit[$form_element_name] = '';
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published'));
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
$this->nodeStorage->resetCache([$node->id()]);
$node = $this->nodeStorage->load($node->id());
$uid = $node->getOwnerId();
@ -228,7 +274,7 @@ class NodeEditFormTest extends NodeTestBase {
// Change the authored by field to another user's name (that is not
// logged in).
$edit[$form_element_name] = $this->webUser->getUsername();
$this->drupalPostForm(NULL, $edit, t('Save and keep published'));
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->nodeStorage->resetCache([$node->id()]);
$node = $this->nodeStorage->load($node->id());
$this->assertIdentical($node->getOwnerId(), $this->webUser->id(), 'Node authored by normal user.');

View file

@ -1,135 +0,0 @@
<?php
namespace Drupal\Tests\node\Functional;
/**
* Tests all the different buttons on the node form.
*
* @group node
*/
class NodeFormButtonsTest extends NodeTestBase {
use AssertButtonsTrait;
/**
* A normal logged in user.
*
* @var \Drupal\user\UserInterface
*/
protected $webUser;
/**
* A user with permission to bypass access content.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
protected function setUp() {
parent::setUp();
// Create a user that has no access to change the state of the node.
$this->webUser = $this->drupalCreateUser(['create article content', 'edit own article content']);
// Create a user that has access to change the state of the node.
$this->adminUser = $this->drupalCreateUser(['administer nodes', 'bypass node access']);
}
/**
* Tests that the right buttons are displayed for saving nodes.
*/
public function testNodeFormButtons() {
$node_storage = $this->container->get('entity.manager')->getStorage('node');
// Log in as administrative user.
$this->drupalLogin($this->adminUser);
// Verify the buttons on a node add form.
$this->drupalGet('node/add/article');
$this->assertButtons([t('Save and publish'), t('Save as unpublished')]);
// Save the node and assert it's published after clicking
// 'Save and publish'.
$edit = ['title[0][value]' => $this->randomString()];
$this->drupalPostForm('node/add/article', $edit, t('Save and publish'));
// Get the node.
$node_1 = $node_storage->load(1);
$this->assertTrue($node_1->isPublished(), 'Node is published');
// Verify the buttons on a node edit form.
$this->drupalGet('node/' . $node_1->id() . '/edit');
$this->assertButtons([t('Save and keep published'), t('Save and unpublish')]);
// Save the node and verify it's still published after clicking
// 'Save and keep published'.
$this->drupalPostForm(NULL, $edit, t('Save and keep published'));
$node_storage->resetCache([1]);
$node_1 = $node_storage->load(1);
$this->assertTrue($node_1->isPublished(), 'Node is published');
// Save the node and verify it's unpublished after clicking
// 'Save and unpublish'.
$this->drupalPostForm('node/' . $node_1->id() . '/edit', $edit, t('Save and unpublish'));
$node_storage->resetCache([1]);
$node_1 = $node_storage->load(1);
$this->assertFalse($node_1->isPublished(), 'Node is unpublished');
// Verify the buttons on an unpublished node edit screen.
$this->drupalGet('node/' . $node_1->id() . '/edit');
$this->assertButtons([t('Save and keep unpublished'), t('Save and publish')]);
// Create a node as a normal user.
$this->drupalLogout();
$this->drupalLogin($this->webUser);
// Verify the buttons for a normal user.
$this->drupalGet('node/add/article');
$this->assertButtons([t('Save')], FALSE);
// Create the node.
$edit = ['title[0][value]' => $this->randomString()];
$this->drupalPostForm('node/add/article', $edit, t('Save'));
$node_2 = $node_storage->load(2);
$this->assertTrue($node_2->isPublished(), 'Node is published');
// Log in as an administrator and unpublish the node that just
// was created by the normal user.
$this->drupalLogout();
$this->drupalLogin($this->adminUser);
$this->drupalPostForm('node/' . $node_2->id() . '/edit', [], t('Save and unpublish'));
$node_storage->resetCache([2]);
$node_2 = $node_storage->load(2);
$this->assertFalse($node_2->isPublished(), 'Node is unpublished');
// Log in again as the normal user, save the node and verify
// it's still unpublished.
$this->drupalLogout();
$this->drupalLogin($this->webUser);
$this->drupalPostForm('node/' . $node_2->id() . '/edit', [], t('Save'));
$node_storage->resetCache([2]);
$node_2 = $node_storage->load(2);
$this->assertFalse($node_2->isPublished(), 'Node is still unpublished');
$this->drupalLogout();
// Set article content type default to unpublished. This will change the
// the initial order of buttons and/or status of the node when creating
// a node.
$fields = \Drupal::entityManager()->getFieldDefinitions('node', 'article');
$fields['status']->getConfig('article')
->setDefaultValue(FALSE)
->save();
// Verify the buttons on a node add form for an administrator.
$this->drupalLogin($this->adminUser);
$this->drupalGet('node/add/article');
$this->assertButtons([t('Save as unpublished'), t('Save and publish')]);
// Verify the node is unpublished by default for a normal user.
$this->drupalLogout();
$this->drupalLogin($this->webUser);
$edit = ['title[0][value]' => $this->randomString()];
$this->drupalPostForm('node/add/article', $edit, t('Save'));
$node_3 = $node_storage->load(3);
$this->assertFalse($node_3->isPublished(), 'Node is unpublished');
}
}

View file

@ -14,7 +14,7 @@ class NodeHelpTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array.
* @var array
*/
public static $modules = ['block', 'node', 'help'];

View file

@ -0,0 +1,62 @@
<?php
namespace Drupal\Tests\node\Functional;
use Drupal\Core\Session\AccountInterface;
use Drupal\Tests\BrowserTestBase;
use Drupal\user\Entity\Role;
/**
* Tests the node entity preview functionality for anonymous user.
*
* @group node
*/
class NodePreviewAnonymousTest extends BrowserTestBase {
/**
* Enable node module to test on the preview.
*
* @var array
*/
public static $modules = ['node'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Create Basic page node type.
$this->drupalCreateContentType([
'type' => 'page',
'name' => 'Basic page',
'display_submitted' => FALSE,
]);
// Grant create and editing permissions to anonymous user:
$anonymous_role = Role::load(AccountInterface::ANONYMOUS_ROLE);
$anonymous_role->grantPermission('create page content');
$anonymous_role->save();
}
/**
* Checks the node preview functionality for anonymous users.
*/
public function testAnonymousPagePreview() {
$title_key = 'title[0][value]';
$body_key = 'body[0][value]';
// Fill in node creation form and preview node.
$edit = [
$title_key => $this->randomMachineName(),
$body_key => $this->randomMachineName(),
];
$this->drupalPostForm('node/add/page', $edit, t('Preview'));
// Check that the preview is displaying the title, body and term.
$this->assertSession()->linkExists(t('Back to content editing'));
$this->assertSession()->responseContains($edit[$body_key]);
$this->assertSession()->titleEquals($edit[$title_key] . ' | Drupal');
}
}

View file

@ -26,6 +26,13 @@ class NodeRevisionsAllTest extends NodeTestBase {
*/
protected $revisionLogs;
/**
* An arbitrary user for revision authoring.
*
* @var \Drupal\user\UserInterface
*/
protected $revisionUser;
/**
* {@inheritdoc}
*/
@ -39,7 +46,7 @@ class NodeRevisionsAllTest extends NodeTestBase {
'revert page revisions',
'delete page revisions',
'edit any page content',
'delete any page content'
'delete any page content',
]
);
$this->drupalLogin($web_user);
@ -47,6 +54,10 @@ class NodeRevisionsAllTest extends NodeTestBase {
// Create an initial node.
$node = $this->drupalCreateNode();
// Create a user for revision authoring.
// This must be different from user performing revert.
$this->revisionUser = $this->drupalCreateUser();
$settings = get_object_vars($node);
$settings['revision'] = 1;
@ -86,6 +97,8 @@ class NodeRevisionsAllTest extends NodeTestBase {
'format' => filter_default_format(),
];
$node->setNewRevision();
// Ensure the revision author is a different user.
$node->setRevisionUserId($this->revisionUser->id());
$node->save();
return $node;
@ -109,7 +122,7 @@ class NodeRevisionsAllTest extends NodeTestBase {
'revert all revisions',
'delete all revisions',
'edit any page content',
'delete any page content'
'delete any page content',
]
);
$this->drupalLogin($content_admin);
@ -134,13 +147,18 @@ class NodeRevisionsAllTest extends NodeTestBase {
[
'@type' => 'Basic page',
'%title' => $nodes[1]->getTitle(),
'%revision-date' => format_date($nodes[1]->getRevisionCreationTime())
'%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() != $this->revisionUser->id(), 'Node revision author is not original revision author.');
// Confirm that this is not the current version.
$node = node_revision_load($node->getRevisionId());
$this->assertFalse($node->isDefaultRevision(), 'Third node revision is not the current one.');

View file

@ -0,0 +1,451 @@
<?php
namespace Drupal\Tests\node\Functional;
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 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 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();
}
}
}

View file

@ -67,7 +67,7 @@ class NodeRevisionsUiBypassAccessTest extends NodeTestBase {
// Uncheck the create new revision checkbox and save the node.
$edit = ['revision' => FALSE];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, 'Save and keep published');
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, 'Save');
$this->assertUrl($node->toUrl());
$this->assertNoLink(t('Revisions'));
@ -78,7 +78,7 @@ class NodeRevisionsUiBypassAccessTest extends NodeTestBase {
// Submit the form without changing the checkbox.
$edit = [];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, 'Save and keep published');
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, 'Save');
$this->assertUrl($node->toUrl());
$this->assertLink(t('Revisions'));

View file

@ -55,7 +55,7 @@ class NodeRevisionsUiTest extends NodeTestBase {
// Uncheck the create new revision checkbox and save the node.
$edit = ['revision' => FALSE];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published'));
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
// Load the node again and check the revision is the same as before.
$node_storage->resetCache([$node->id()]);
@ -68,7 +68,7 @@ class NodeRevisionsUiTest extends NodeTestBase {
// Submit the form without changing the checkbox.
$edit = [];
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published'));
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save'));
// Load the node again and check the revision is different from before.
$node_storage->resetCache([$node->id()]);
@ -160,10 +160,17 @@ class NodeRevisionsUiTest extends NodeTestBase {
$this->drupalGet('node/' . $node_id . '/revisions');
// Verify that the latest affected revision having been a default revision
// is displayed as the current one.
$this->assertNoLinkByHref('/node/' . $node_id . '/revisions/1/revert');
$elements = $this->xpath('//tr[contains(@class, "revision-current")]/td/a[1]');
// The site may be installed in a subdirectory, so check if the URL is
// contained in the retrieved one.
$this->assertContains('/node/1', current($elements)->getAttribute('href'));
// Verify that the default revision can be an older revision than the latest
// one.
// Assert that the revisions with translations changes are shown: 1 and 4.
$this->assertLinkByHref('/node/' . $node_id . '/revisions/1/revert');
// Assert that the revisions with translations changes are shown.
$this->assertLinkByHref('/node/' . $node_id . '/revisions/4/revert');
// Assert that the revisions without translations changes are filtered out:

View file

@ -109,8 +109,10 @@ class NodeSaveTest extends NodeTestBase {
'uid' => $this->webUser->id(),
'type' => 'article',
'title' => $this->randomMachineName(8),
'created' => 280299600, // Sun, 19 Nov 1978 05:00:00 GMT
'changed' => 979534800, // Drupal 1.0 release.
// Sun, 19 Nov 1978 05:00:00 GMT.
'created' => 280299600,
// Drupal 1.0 release.
'changed' => 979534800,
];
Node::create($edit)->save();

View file

@ -102,7 +102,7 @@ abstract class NodeTestBase extends BrowserTestBase {
[
'@result' => $result ? 'true' : 'false',
'%op' => $operation,
'%langcode' => !empty($langcode) ? $langcode : 'empty'
'%langcode' => !empty($langcode) ? $langcode : 'empty',
]
);
}

View file

@ -21,13 +21,16 @@ class NodeTranslationUITest extends ContentTranslationUITestBase {
*/
protected $defaultCacheContexts = [
'languages:language_interface',
'session',
'theme',
'route',
'timezone',
'url.path.parent',
'url.query_args:_wrapper_format',
'user'
'user.roles',
'url.path.is_front',
// These two cache contexts are added by BigPipe.
'cookies:big_pipe_nojs',
'session.exists',
];
/**
@ -97,9 +100,11 @@ class NodeTranslationUITest extends ContentTranslationUITestBase {
$add_url = Url::fromRoute("entity.$entity_type_id.content_translation_add", [
$entity->getEntityTypeId() => $entity->id(),
'source' => $default_langcode,
'target' => $langcode
'target' => $langcode,
], ['language' => $language]);
$this->drupalPostForm($add_url, $this->getEditValues($values, $langcode), t('Save and unpublish (this translation)'));
$edit = $this->getEditValues($values, $langcode);
$edit['status[value]'] = FALSE;
$this->drupalPostForm($add_url, $edit, t('Save (this translation)'));
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
@ -136,18 +141,6 @@ class NodeTranslationUITest extends ContentTranslationUITestBase {
return ['title' => [['value' => $this->randomMachineName()]]] + parent::getNewEntityValues($langcode);
}
/**
* {@inheritdoc}
*/
protected function getFormSubmitAction(EntityInterface $entity, $langcode) {
if ($entity->getTranslation($langcode)->isPublished()) {
return t('Save and keep published') . $this->getFormSubmitSuffix($entity, $langcode);
}
else {
return t('Save and keep unpublished') . $this->getFormSubmitSuffix($entity, $langcode);
}
}
/**
* {@inheritdoc}
*/
@ -158,18 +151,18 @@ class NodeTranslationUITest extends ContentTranslationUITestBase {
$entity = $storage->load($this->entityId);
$languages = $this->container->get('language_manager')->getLanguages();
$actions = [
t('Save and keep published'),
t('Save and unpublish'),
$statuses = [
TRUE,
FALSE,
];
foreach ($actions as $index => $action) {
foreach ($statuses as $index => $value) {
// (Un)publish the node translations and check that the translation
// statuses are (un)published accordingly.
foreach ($this->langcodes as $langcode) {
$options = ['language' => $languages[$langcode]];
$url = $entity->urlInfo('edit-form', $options);
$this->drupalPostForm($url, [], $action . $this->getFormSubmitSuffix($entity, $langcode), $options);
$this->drupalPostForm($url, ['status[value]' => $value], t('Save') . $this->getFormSubmitSuffix($entity, $langcode), $options);
}
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
@ -292,7 +285,7 @@ class NodeTranslationUITest extends ContentTranslationUITestBase {
$translation = $node->addTranslation($langcode, $values[$langcode]);
// Publish and promote the translation to frontpage.
$translation->setPromoted(TRUE);
$translation->setPublished(TRUE);
$translation->setPublished();
}
$node->save();
@ -509,4 +502,28 @@ class NodeTranslationUITest extends ContentTranslationUITestBase {
$this->assertNoText('First rev en title');
}
/**
* Test that title is not escaped (but XSS-filtered) for details form element.
*/
public function testDetailsTitleIsNotEscaped() {
$this->drupalLogin($this->administrator);
// Make the image field a multi-value field in order to display a
// details form element.
$edit = ['cardinality_number' => 2];
$this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.field_image/storage', $edit, t('Save field settings'));
// Make the image field non-translatable.
$edit = ['settings[node][article][fields][field_image]' => FALSE];
$this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
// Create a node.
$nid = $this->createEntity(['title' => 'Node with multi-value image field en title'], 'en');
// Add a French translation and assert the title markup is not escaped.
$this->drupalGet("node/$nid/translations/add/en/fr");
$markup = 'Image <span class="translation-entity-all-languages">(all languages)</span>';
$this->assertSession()->assertNoEscaped($markup);
$this->assertSession()->responseContains($markup);
}
}

View file

@ -0,0 +1,262 @@
<?php
namespace Drupal\Tests\node\Functional;
use Drupal\field\Entity\FieldConfig;
use Drupal\node\Entity\NodeType;
use Drupal\Core\Url;
use Drupal\Tests\system\Functional\Menu\AssertBreadcrumbTrait;
use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
/**
* Ensures that node type functions work correctly.
*
* @group node
*/
class NodeTypeTest extends NodeTestBase {
use AssertBreadcrumbTrait;
use AssertPageCacheContextsAndTagsTrait;
/**
* 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() {
$assert = $this->assertSession();
$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');
$assert->pageTextContains('Title');
$assert->pageTextContains('Body');
// 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');
$assert->pageTextContains('Foo');
$assert->pageTextNotContains('Title');
// 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');
$assert->pageTextContains('Bar');
$assert->pageTextContains('Lorem ipsum');
$this->clickLink('Bar');
$assert->pageTextContains('Foo');
$assert->pageTextContains('Body');
// 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');
$assert->pageTextNotContains('Body');
}
/**
* 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.');
}
}

View file

@ -2,7 +2,6 @@
namespace Drupal\Tests\node\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Tests\BrowserTestBase;
@ -83,6 +82,11 @@ class NodeTypeTranslationTest extends BrowserTestBase {
protected function installParameters() {
$parameters = parent::installParameters();
$parameters['parameters']['langcode'] = $this->defaultLangcode;
// Create an empty po file so we don't attempt to download one from
// localize.drupal.org. It does not need to match the version exactly as the
// multi-lingual system will fallback.
\Drupal::service('file_system')->mkdir($this->publicFilesDirectory . '/translations', NULL, TRUE);
file_put_contents($this->publicFilesDirectory . "/translations/drupal-8.0.0.{$this->defaultLangcode}.po", '');
return $parameters;
}
@ -90,7 +94,7 @@ class NodeTypeTranslationTest extends BrowserTestBase {
* Tests the node type translation.
*/
public function testNodeTypeTranslation() {
$type = Unicode::strtolower($this->randomMachineName(16));
$type = mb_strtolower($this->randomMachineName(16));
$name = $this->randomString();
$this->drupalLogin($this->adminUser);
$this->drupalCreateContentType(['type' => $type, 'name' => $name]);
@ -124,7 +128,7 @@ class NodeTypeTranslationTest extends BrowserTestBase {
* Tests the node type title label translation.
*/
public function testNodeTypeTitleLabelTranslation() {
$type = Unicode::strtolower($this->randomMachineName(16));
$type = mb_strtolower($this->randomMachineName(16));
$name = $this->randomString();
$this->drupalLogin($this->adminUser);
$this->drupalCreateContentType(['type' => $type, 'name' => $name]);
@ -154,7 +158,7 @@ class NodeTypeTranslationTest extends BrowserTestBase {
$this->drupalPostForm(NULL, [], 'Save field settings');
$this->drupalPostForm(NULL, [], 'Save settings');
$type = Unicode::strtolower($this->randomMachineName(16));
$type = mb_strtolower($this->randomMachineName(16));
$name = $this->randomString();
$this->drupalCreateContentType(['type' => $type, 'name' => $name]);

View file

@ -47,7 +47,7 @@ class NodeViewTest extends NodeTestBase {
// ensure caches are handled properly.
$this->drupalLogin($this->rootUser);
$edit = [
'anonymous[edit own ' . $node->bundle() . ' content]' => TRUE
'anonymous[edit own ' . $node->bundle() . ' content]' => TRUE,
];
$this->drupalPostForm('admin/people/permissions', $edit, 'Save permissions');
$this->drupalLogout();

View file

@ -0,0 +1,480 @@
<?php
namespace Drupal\Tests\node\Functional;
use Drupal\comment\Tests\CommentTestTrait;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url;
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;
use Drupal\Tests\field\Traits\EntityReferenceTestTrait;
use Drupal\Tests\TestFileCreationTrait;
/**
* Tests the node entity preview functionality.
*
* @group node
*/
class PagePreviewTest extends NodeTestBase {
use EntityReferenceTestTrait;
use CommentTestTrait;
use TestFileCreationTrait {
getTestFiles as drupalGetTestFiles;
}
/**
* 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.
$expected_title = $edit[$title_key] . ' | Drupal';
$this->assertSession()->titleEquals($expected_title);
$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->getSession()->getPage()->pressButton('Add another item');
$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->assertSession()->titleEquals($expected_title);
$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->getSession()->getPage()->pressButton('Add another item');
$this->getSession()->getPage()->pressButton('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]);
}
}

View file

@ -10,6 +10,7 @@ use Drupal\node\Entity\Node;
* @group node
*/
class PageViewTest extends NodeTestBase {
/**
* Tests an anonymous and unpermissioned user attempting to edit the node.
*/

View file

@ -0,0 +1,24 @@
<?php
namespace Drupal\Tests\node\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* @group rest
*/
class NodeJsonAnonTest extends NodeResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
}

View file

@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\node\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group rest
*/
class NodeJsonBasicAuthTest extends NodeResourceTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,29 @@
<?php
namespace Drupal\Tests\node\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group rest
*/
class NodeJsonCookieTest extends NodeResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,264 @@
<?php
namespace Drupal\Tests\node\Functional\Rest;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
use Drupal\user\Entity\User;
use GuzzleHttp\RequestOptions;
abstract class NodeResourceTestBase extends EntityResourceTestBase {
use BcTimestampNormalizerUnixTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['node', 'path'];
/**
* {@inheritdoc}
*/
protected static $entityTypeId = 'node';
/**
* {@inheritdoc}
*/
protected static $patchProtectedFieldNames = [
'revision_timestamp' => NULL,
'revision_uid' => NULL,
'created' => "The 'administer nodes' permission is required.",
'changed' => NULL,
'promote' => "The 'administer nodes' permission is required.",
'sticky' => "The 'administer nodes' permission is required.",
'path' => "The following permissions are required: 'create url aliases' OR 'administer url aliases'.",
];
/**
* @var \Drupal\node\NodeInterface
*/
protected $entity;
/**
* {@inheritdoc}
*/
protected function setUpAuthorization($method) {
switch ($method) {
case 'GET':
$this->grantPermissionsToTestedRole(['access content']);
break;
case 'POST':
$this->grantPermissionsToTestedRole(['access content', 'create camelids content']);
break;
case 'PATCH':
// Do not grant the 'create url aliases' permission to test the case
// when the path field is protected/not accessible, see
// \Drupal\Tests\rest\Functional\EntityResource\Term\TermResourceTestBase
// for a positive test.
$this->grantPermissionsToTestedRole(['access content', 'edit any camelids content']);
break;
case 'DELETE':
$this->grantPermissionsToTestedRole(['access content', 'delete any camelids content']);
break;
}
}
/**
* {@inheritdoc}
*/
protected function createEntity() {
if (!NodeType::load('camelids')) {
// Create a "Camelids" node type.
NodeType::create([
'name' => 'Camelids',
'type' => 'camelids',
])->save();
}
// Create a "Llama" node.
$node = Node::create(['type' => 'camelids']);
$node->setTitle('Llama')
->setOwnerId(static::$auth ? $this->account->id() : 0)
->setPublished()
->setCreatedTime(123456789)
->setChangedTime(123456789)
->setRevisionCreationTime(123456789)
->set('path', '/llama')
->save();
return $node;
}
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
$author = User::load($this->entity->getOwnerId());
return [
'nid' => [
['value' => 1],
],
'uuid' => [
['value' => $this->entity->uuid()],
],
'vid' => [
['value' => 1],
],
'langcode' => [
[
'value' => 'en',
],
],
'type' => [
[
'target_id' => 'camelids',
'target_type' => 'node_type',
'target_uuid' => NodeType::load('camelids')->uuid(),
],
],
'title' => [
[
'value' => 'Llama',
],
],
'status' => [
[
'value' => TRUE,
],
],
'created' => [
$this->formatExpectedTimestampItemValues(123456789),
],
'changed' => [
$this->formatExpectedTimestampItemValues($this->entity->getChangedTime()),
],
'promote' => [
[
'value' => TRUE,
],
],
'sticky' => [
[
'value' => FALSE,
],
],
'revision_timestamp' => [
$this->formatExpectedTimestampItemValues(123456789),
],
'revision_translation_affected' => [
[
'value' => TRUE,
],
],
'default_langcode' => [
[
'value' => TRUE,
],
],
'uid' => [
[
'target_id' => (int) $author->id(),
'target_type' => 'user',
'target_uuid' => $author->uuid(),
'url' => base_path() . 'user/' . $author->id(),
],
],
'revision_uid' => [
[
'target_id' => (int) $author->id(),
'target_type' => 'user',
'target_uuid' => $author->uuid(),
'url' => base_path() . 'user/' . $author->id(),
],
],
'revision_log' => [],
'path' => [
[
'alias' => '/llama',
'pid' => 1,
'langcode' => 'en',
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
return [
'type' => [
[
'target_id' => 'camelids',
],
],
'title' => [
[
'value' => 'Dramallama',
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getExpectedUnauthorizedAccessMessage($method) {
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
return parent::getExpectedUnauthorizedAccessMessage($method);
}
if ($method === 'GET' || $method == 'PATCH' || $method == 'DELETE') {
return "The 'access content' permission is required.";
}
return parent::getExpectedUnauthorizedAccessMessage($method);
}
/**
* Tests PATCHing a node's path with and without 'create url aliases'.
*
* For a positive test, see the similar test coverage for Term.
*
* @see \Drupal\Tests\rest\Functional\EntityResource\Term\TermResourceTestBase::testPatchPath()
*/
public function testPatchPath() {
$this->initAuthentication();
$this->provisionEntityResource();
$this->setUpAuthorization('GET');
$this->setUpAuthorization('PATCH');
$url = $this->getEntityResourceUrl()->setOption('query', ['_format' => static::$format]);
// GET node's current normalization.
$response = $this->request('GET', $url, $this->getAuthenticationRequestOptions('GET'));
$normalization = $this->serializer->decode((string) $response->getBody(), static::$format);
// Change node's path alias.
$normalization['path'][0]['alias'] .= 's-rule-the-world';
// Create node PATCH request.
$request_options = [];
$request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType;
$request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
// PATCH request: 403 when creating URL aliases unauthorized. Before
// asserting the 403 response, assert that the stored path alias remains
// unchanged.
$response = $this->request('PATCH', $url, $request_options);
$this->assertSame('/llama', $this->entityStorage->loadUnchanged($this->entity->id())->get('path')->alias);
$this->assertResourceErrorResponse(403, "Access denied on updating field 'path'. " . static::$patchProtectedFieldNames['path'], $response);
// Grant permission to create URL aliases.
$this->grantPermissionsToTestedRole(['create url aliases']);
// Repeat PATCH request: 200.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceResponse(200, FALSE, $response);
$updated_normalization = $this->serializer->decode((string) $response->getBody(), static::$format);
$this->assertSame($normalization['path'], $updated_normalization['path']);
}
}

View file

@ -0,0 +1,24 @@
<?php
namespace Drupal\Tests\node\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* @group rest
*/
class NodeTypeJsonAnonTest extends NodeTypeResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
}

View file

@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\node\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group rest
*/
class NodeTypeJsonBasicAuthTest extends NodeTypeResourceTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,29 @@
<?php
namespace Drupal\Tests\node\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group rest
*/
class NodeTypeJsonCookieTest extends NodeTypeResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,90 @@
<?php
namespace Drupal\Tests\node\Functional\Rest;
use Drupal\node\Entity\NodeType;
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
/**
* ResourceTestBase for NodeType entity.
*/
abstract class NodeTypeResourceTestBase extends EntityResourceTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['node'];
/**
* {@inheritdoc}
*/
protected static $entityTypeId = 'node_type';
/**
* The NodeType entity.
*
* @var \Drupal\node\NodeTypeInterface
*/
protected $entity;
/**
* {@inheritdoc}
*/
protected function setUpAuthorization($method) {
$this->grantPermissionsToTestedRole(['administer content types', 'access content']);
}
/**
* {@inheritdoc}
*/
protected function createEntity() {
// Create a "Camelids" node type.
$camelids = NodeType::create([
'name' => 'Camelids',
'type' => 'camelids',
'description' => 'Camelids are large, strictly herbivorous animals with slender necks and long legs.',
]);
$camelids->save();
return $camelids;
}
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
return [
'dependencies' => [],
'description' => 'Camelids are large, strictly herbivorous animals with slender necks and long legs.',
'display_submitted' => TRUE,
'help' => NULL,
'langcode' => 'en',
'name' => 'Camelids',
'new_revision' => TRUE,
'preview_mode' => 1,
'status' => TRUE,
'type' => 'camelids',
'uuid' => $this->entity->uuid(),
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
// @todo Update in https://www.drupal.org/node/2300677.
}
/**
* {@inheritdoc}
*/
protected function getExpectedUnauthorizedAccessMessage($method) {
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
return parent::getExpectedUnauthorizedAccessMessage($method);
}
return "The 'access content' permission is required.";
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace Drupal\Tests\node\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class NodeTypeXmlAnonTest extends NodeTypeResourceTestBase {
use AnonResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
}

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\Tests\node\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class NodeTypeXmlBasicAuthTest extends NodeTypeResourceTestBase {
use BasicAuthResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}

View file

@ -0,0 +1,31 @@
<?php
namespace Drupal\Tests\node\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class NodeTypeXmlCookieTest extends NodeTypeResourceTestBase {
use CookieResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}

View file

@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\node\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class NodeXmlAnonTest extends NodeResourceTestBase {
use AnonResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
public function testPatchPath() {
// Deserialization of the XML format is not supported.
$this->markTestSkipped();
}
}

View file

@ -0,0 +1,44 @@
<?php
namespace Drupal\Tests\node\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class NodeXmlBasicAuthTest extends NodeResourceTestBase {
use BasicAuthResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
/**
* {@inheritdoc}
*/
public function testPatchPath() {
// Deserialization of the XML format is not supported.
$this->markTestSkipped();
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace Drupal\Tests\node\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class NodeXmlCookieTest extends NodeResourceTestBase {
use CookieResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
/**
* {@inheritdoc}
*/
public function testPatchPath() {
// Deserialization of the XML format is not supported.
$this->markTestSkipped();
}
}

View file

@ -0,0 +1,68 @@
<?php
namespace Drupal\Tests\node\Functional\Update;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
/**
* Tests that node settings are properly updated during database updates.
*
* @group node
* @group legacy
*/
class NodeUpdateTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8-rc1.bare.standard.php.gz',
];
}
/**
* Tests that the node entity type has a 'published' entity key.
*
* @see node_update_8301()
*/
public function testPublishedEntityKey() {
// Check that the 'published' entity key does not exist prior to the update.
$entity_type = \Drupal::entityDefinitionUpdateManager()->getEntityType('node');
$this->assertFalse($entity_type->getKey('published'));
// Run updates.
$this->runUpdates();
// Check that the entity key exists and it has the correct value.
$entity_type = \Drupal::entityDefinitionUpdateManager()->getEntityType('node');
$this->assertEqual('status', $entity_type->getKey('published'));
}
/**
* Tests that the node entity form has the status checkbox.
*
* @see node_post_update_configure_status_field_widget()
*/
public function testStatusCheckbox() {
// Run updates.
$this->runUpdates();
$query = \Drupal::entityQuery('entity_form_display')
->condition('targetEntityType', 'node');
$ids = $query->execute();
$form_displays = EntityFormDisplay::loadMultiple($ids);
/**
* @var string $id
* @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display
*/
foreach ($form_displays as $id => $form_display) {
$component = $form_display->getComponent('status');
$this->assertEqual('boolean_checkbox', $component['type']);
$this->assertEqual(['display_label' => TRUE], $component['settings']);
}
}
}

View file

@ -2,7 +2,7 @@
namespace Drupal\Tests\node\Functional\Views;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
@ -67,9 +67,9 @@ class BulkFormAccessTest extends NodeTestBase {
// Create a private node (author may view, edit and delete, others may not).
$node = $this->drupalCreateNode([
'type' => 'article',
'private' => [[
'value' => TRUE,
]],
'private' => [
['value' => TRUE],
],
'uid' => $author->id(),
]);
// Create an account that may view the private node, but not edit it.
@ -88,7 +88,7 @@ class BulkFormAccessTest extends NodeTestBase {
'action' => 'node_unpublish_action',
];
$this->drupalPostForm('test-node-bulk-form', $edit, t('Apply to selected items'));
$this->assertRaw(SafeMarkup::format('No access to execute %action on the @entity_type_label %entity_label.', [
$this->assertRaw(new FormattableMarkup('No access to execute %action on the @entity_type_label %entity_label.', [
'%action' => 'Unpublish content',
'@entity_type_label' => 'Content',
'%entity_label' => $node->label(),
@ -117,7 +117,7 @@ class BulkFormAccessTest extends NodeTestBase {
];
$this->drupalPostForm('test-node-bulk-form', $edit, t('Apply to selected items'));
// Test that the action message isn't shown.
$this->assertNoRaw(SafeMarkup::format('%action was applied to 1 item.', [
$this->assertNoRaw(new FormattableMarkup('%action was applied to 1 item.', [
'%action' => 'Unpublish content',
]));
// Re-load the node and check the status.
@ -134,9 +134,9 @@ class BulkFormAccessTest extends NodeTestBase {
// Create a private node (author may view, edit and delete, others may not).
$private_node = $this->drupalCreateNode([
'type' => 'article',
'private' => [[
'value' => TRUE,
]],
'private' => [
['value' => TRUE],
],
'uid' => $author->id(),
]);
// Create an account that may view the private node, but not delete it.
@ -146,9 +146,9 @@ class BulkFormAccessTest extends NodeTestBase {
// deleted by the author.
$own_node = $this->drupalCreateNode([
'type' => 'article',
'private' => [[
'value' => TRUE,
]],
'private' => [
['value' => TRUE],
],
'uid' => $account->id(),
]);
$this->drupalLogin($account);

View file

@ -2,7 +2,7 @@
namespace Drupal\Tests\node\Functional\Views;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\views\Views;
@ -55,7 +55,7 @@ class BulkFormTest extends NodeTestBase {
'promote' => FALSE,
];
$node = $this->drupalCreateNode($values);
$this->pass(SafeMarkup::format('Node %title created with language %langcode.', ['%title' => $node->label(), '%langcode' => $node->language()->getId()]));
$this->pass(new FormattableMarkup('Node %title created with language %langcode.', ['%title' => $node->label(), '%langcode' => $node->language()->getId()]));
$this->nodes[] = $node;
}
@ -66,7 +66,7 @@ class BulkFormTest extends NodeTestBase {
if (!$node->hasTranslation($langcode)) {
$title = $this->randomMachineName() . ' [' . $node->id() . ':' . $langcode . ']';
$translation = $node->addTranslation($langcode, ['title' => $title, 'promote' => FALSE]);
$this->pass(SafeMarkup::format('Translation %title created with language %langcode.', ['%title' => $translation->label(), '%langcode' => $translation->language()->getId()]));
$this->pass(new FormattableMarkup('Translation %title created with language %langcode.', ['%title' => $translation->label(), '%langcode' => $translation->language()->getId()]));
}
}
$node->save();
@ -77,7 +77,7 @@ class BulkFormTest extends NodeTestBase {
$langcode = 'en';
$title = $this->randomMachineName() . ' [' . $node->id() . ':' . $langcode . ']';
$translation = $node->addTranslation($langcode, ['title' => $title]);
$this->pass(SafeMarkup::format('Translation %title created with language %langcode.', ['%title' => $translation->label(), '%langcode' => $translation->language()->getId()]));
$this->pass(new FormattableMarkup('Translation %title created with language %langcode.', ['%title' => $translation->label(), '%langcode' => $translation->language()->getId()]));
$node->save();
// Check that all created translations are selected by the test view.
@ -170,19 +170,29 @@ class BulkFormTest extends NodeTestBase {
// operations are always applied to individual translations.
$edit = [
// Original and all translations.
'node_bulk_form[0]' => TRUE, // Node 1, English, original.
'node_bulk_form[1]' => TRUE, // Node 1, British English.
'node_bulk_form[2]' => TRUE, // Node 1, Italian.
// Node 1, English, original.
'node_bulk_form[0]' => TRUE,
// Node 1, British English.
'node_bulk_form[1]' => TRUE,
// Node 1, Italian.
'node_bulk_form[2]' => TRUE,
// Original and only one translation.
'node_bulk_form[3]' => TRUE, // Node 2, English.
'node_bulk_form[4]' => TRUE, // Node 2, British English, original.
'node_bulk_form[5]' => FALSE, // Node 2, Italian.
// Node 2, English.
'node_bulk_form[3]' => TRUE,
// Node 2, British English, original.
'node_bulk_form[4]' => TRUE,
// Node 2, Italian.
'node_bulk_form[5]' => FALSE,
// Only a single translation.
'node_bulk_form[6]' => TRUE, // Node 3, English.
'node_bulk_form[7]' => FALSE, // Node 3, Italian, original.
// Node 3, English.
'node_bulk_form[6]' => TRUE,
// Node 3, Italian, original.
'node_bulk_form[7]' => FALSE,
// Only a single untranslated node.
'node_bulk_form[8]' => TRUE, // Node 4, English, untranslated.
'node_bulk_form[9]' => FALSE, // Node 5, British English, untranslated.
// Node 4, English, untranslated.
'node_bulk_form[8]' => TRUE,
// Node 5, British English, untranslated.
'node_bulk_form[9]' => FALSE,
'action' => 'node_unpublish_action',
];
$this->drupalPostForm(NULL, $edit, t('Apply to selected items'));
@ -211,33 +221,43 @@ class BulkFormTest extends NodeTestBase {
// nodes and individual translations are properly deleted.
$edit = [
// Original and all translations.
'node_bulk_form[0]' => TRUE, // Node 1, English, original.
'node_bulk_form[1]' => TRUE, // Node 1, British English.
'node_bulk_form[2]' => TRUE, // Node 1, Italian.
// Node 1, English, original.
'node_bulk_form[0]' => TRUE,
// Node 1, British English.
'node_bulk_form[1]' => TRUE,
// Node 1, Italian.
'node_bulk_form[2]' => TRUE,
// Original and only one translation.
'node_bulk_form[3]' => TRUE, // Node 2, English.
'node_bulk_form[4]' => TRUE, // Node 2, British English, original.
'node_bulk_form[5]' => FALSE, // Node 2, Italian.
// Node 2, English.
'node_bulk_form[3]' => TRUE,
// Node 2, British English, original.
'node_bulk_form[4]' => TRUE,
// Node 2, Italian.
'node_bulk_form[5]' => FALSE,
// Only a single translation.
'node_bulk_form[6]' => TRUE, // Node 3, English.
'node_bulk_form[7]' => FALSE, // Node 3, Italian, original.
// Node 3, English.
'node_bulk_form[6]' => TRUE,
// Node 3, Italian, original.
'node_bulk_form[7]' => FALSE,
// Only a single untranslated node.
'node_bulk_form[8]' => TRUE, // Node 4, English, untranslated.
'node_bulk_form[9]' => FALSE, // Node 5, British English, untranslated.
// Node 4, English, untranslated.
'node_bulk_form[8]' => TRUE,
// Node 5, British English, untranslated.
'node_bulk_form[9]' => FALSE,
'action' => 'node_delete_action',
];
$this->drupalPostForm(NULL, $edit, t('Apply to selected items'));
$label = $this->loadNode(1)->label();
$this->assertText("$label (Original translation) - The following content translations will be deleted:");
$this->assertText("$label (Original translation) - The following content item translations will be deleted:");
$label = $this->loadNode(2)->label();
$this->assertText("$label (Original translation) - The following content translations will be deleted:");
$this->assertText("$label (Original translation) - The following content item translations will be deleted:");
$label = $this->loadNode(3)->getTranslation('en')->label();
$this->assertText($label);
$this->assertNoText("$label (Original translation) - The following content translations will be deleted:");
$this->assertNoText("$label (Original translation) - The following content item translations will be deleted:");
$label = $this->loadNode(4)->label();
$this->assertText($label);
$this->assertNoText("$label (Original translation) - The following content translations will be deleted:");
$this->assertNoText("$label (Original translation) - The following content item translations will be deleted:");
$this->drupalPostForm(NULL, [], t('Delete'));
@ -253,7 +273,7 @@ class BulkFormTest extends NodeTestBase {
$node = $this->loadNode(5);
$this->assertTrue($node, '5: Node has not been deleted');
$this->assertText('Deleted 8 posts.');
$this->assertText('Deleted 8 content items.');
}
/**

View file

@ -54,10 +54,12 @@ class FilterNodeAccessTest extends NodeTestBase {
$this->drupalLogin($web_user);
foreach ([0 => 'Public', 1 => 'Private'] as $is_private => $type) {
$settings = [
'body' => [[
'value' => $type . ' node',
'format' => filter_default_format(),
]],
'body' => [
[
'value' => $type . ' node',
'format' => filter_default_format(),
],
],
'title' => t('@private_public Article created by @user', ['@private_public' => $type, '@user' => $web_user->getUsername()]),
'type' => 'article',
'uid' => $web_user->id(),

View file

@ -284,7 +284,7 @@ class FrontPageTest extends ViewTestBase {
[
'value' => $this->randomMachineName(32),
'format' => filter_default_format(),
]
],
],
'type' => 'article',
'created' => $i,

View file

@ -0,0 +1,47 @@
<?php
namespace Drupal\Tests\node\Functional\Views;
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'];
/**
* 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->passRaw = 'new_password';
$admin_user->save();
$this->drupalCreateContentType(['type' => 'page']);
$this->drupalCreateNode(['promote' => 1]);
$this->drupalLogin($admin_user);
$this->drupalGet('node');
}
}

View file

@ -75,7 +75,7 @@ class NodeLanguageTest extends NodeTestBase {
],
'fr' => [
'Premier nœud fr',
]
],
];
// Create nodes with translations.

View file

@ -45,16 +45,19 @@ class NodeRevisionWizardTest extends WizardTestBase {
$view['show[wizard_key]'] = 'node_revision';
$this->drupalPostForm('admin/structure/views/add', $view, t('Save and edit'));
$view_storage_controller = \Drupal::entityManager()->getStorage('view');
/** @var \Drupal\views\Entity\View $view */
$view = $view_storage_controller->load($view['id']);
$view = Views::getView($view['id']);
$view->initHandlers();
$this->assertEqual($view->get('base_table'), 'node_field_revision');
$this->assertEqual($view->getBaseTables(), ['node_field_revision' => TRUE, '#global' => TRUE]);
$executable = Views::executableFactory()->get($view);
$this->executeView($executable);
// Check for the default filters.
$this->assertEqual($view->filter['status']->table, 'node_field_revision');
$this->assertEqual($view->filter['status']->field, 'status');
$this->assertTrue($view->filter['status']->value);
$this->assertIdenticalResultset($executable, [['vid' => 1], ['vid' => 3], ['vid' => 2], ['vid' => 4]],
$this->executeView($view);
$this->assertIdenticalResultset($view, [['vid' => 1], ['vid' => 3], ['vid' => 2], ['vid' => 4]],
['vid' => 'vid']);
}

View file

@ -58,12 +58,18 @@ class PathPluginTest extends NodeTestBase {
}
/**
* Tests the node path plugin.
* Tests the node path plugin functionality when converted to entity link.
*/
public function testPathPlugin() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
$view = Views::getView('test_node_path_plugin');
// The configured deprecated node path plugin should be converted to the
// entity link plugin.
$field = $view->getHandler('page_1', 'field', 'path');
$this->assertEqual('entity_link', $field['plugin_id']);
$view->initDisplay();
$view->setDisplay('page_1');
$view->initStyle();

View file

@ -0,0 +1,117 @@
<?php
namespace Drupal\Tests\node\FunctionalJavascript;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\node\Entity\Node;
use Drupal\Tests\contextual\FunctionalJavascript\ContextualLinkClickTrait;
/**
* Create a node with revisions and test contextual links.
*
* @group node
*/
class ContextualLinksTest extends WebDriverTestBase {
use ContextualLinkClickTrait;
/**
* An array of node revisions.
*
* @var \Drupal\node\NodeInterface[]
*/
protected $nodes;
/**
* {@inheritdoc}
*/
protected static $modules = ['node', 'contextual'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalCreateContentType([
'type' => 'page',
'name' => 'Basic page',
'display_submitted' => FALSE,
]);
// Create initial node.
$node = $this->drupalCreateNode();
$nodes = [];
// Get original node.
$nodes[] = clone $node;
// Create two revisions.
$revision_count = 2;
for ($i = 0; $i < $revision_count; $i++) {
// 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->setNewRevision();
$node->save();
// Make sure we get revision information.
$node = Node::load($node->id());
$nodes[] = clone $node;
}
$this->nodes = $nodes;
$this->drupalLogin($this->createUser(
[
'view page revisions',
'revert page revisions',
'delete page revisions',
'edit any page content',
'delete any page content',
'access contextual links',
'administer content types',
]
));
}
/**
* Tests the contextual links on revisions.
*/
public function testRevisionContextualLinks() {
// Confirm that the "Edit" and "Delete" contextual links appear for the
// default revision.
$this->drupalGet('node/' . $this->nodes[0]->id());
$page = $this->getSession()->getPage();
$page->waitFor(10, function () use ($page) {
return $page->find('css', "main .contextual");
});
$this->toggleContextualTriggerVisibility('main');
$page->find('css', 'main .contextual button')->press();
$links = $page->findAll('css', "main .contextual-links li a");
$this->assertEquals('Edit', $links[0]->getText());
$this->assertEquals('Delete', $links[1]->getText());
// Confirm that "Edit" and "Delete" contextual links don't appear for
// non-default revision.
$this->drupalGet("node/" . $this->nodes[0]->id() . "/revisions/" . $this->nodes[1]->getRevisionId() . "/view");
$this->assertSession()->pageTextContains($this->nodes[1]->getTitle());
$page->waitFor(10, function () use ($page) {
return $page->find('css', "main .contextual");
});
$this->toggleContextualTriggerVisibility('main');
$contextual_button = $page->find('css', 'main .contextual button');
$this->assertEmpty(0, $contextual_button);
}
}

View file

@ -0,0 +1,60 @@
<?php
namespace Drupal\Tests\node\FunctionalJavascript;
use Drupal\filter\Entity\FilterFormat;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
/**
* Tests the JavaScript prevention of navigation away from node previews.
*
* @group node
*/
class NodePreviewLinkTest extends WebDriverTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['node', 'filter'];
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$filtered_html_format = FilterFormat::create([
'format' => 'filtered_html',
'name' => 'Filtered HTML',
]);
$filtered_html_format->save();
$this->drupalCreateContentType(['type' => 'test']);
$user = $this->drupalCreateUser([
'access content',
'edit own test content',
'create test content',
$filtered_html_format->getPermissionName(),
]);
$this->drupalLogin($user);
}
/**
* Test the behavior of clicking preview links.
*/
public function testPreviewLinks() {
$assertSession = $this->assertSession();
$this->drupalPostForm('node/add/test', [
'title[0][value]' => 'Test node',
'body[0][value]' => '<a href="#foo">Anchor link</a><a href="/foo">Normal link</a>',
], t('Preview'));
$this->clickLink('Anchor link');
$assertSession->pageTextNotContains('Leave preview?');
$this->clickLink('Normal link');
$assertSession->pageTextContains('Leave preview?');
$this->click('button:contains("Leave preview")');
$this->assertStringEndsWith('/foo', $this->getUrl());
}
}

View file

@ -0,0 +1,51 @@
<?php
namespace Drupal\Tests\node\FunctionalJavascript;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
/**
* Tests the JavaScript updating of summaries on content type form.
*
* @group node
*/
class TestSettingSummariesContentType extends WebDriverTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['node'];
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$admin_user = $this->drupalCreateUser(['administer content types']);
$this->drupalLogin($admin_user);
$this->drupalCreateContentType(['type' => 'test']);
}
/**
* Test a vertical tab 'Workflow' summary.
*/
public function testWorkflowSummary() {
$this->drupalGet('admin/structure/types/manage/test');
$page = $this->getSession()->getPage();
$page->find('css', 'a[href="#edit-workflow"]')->click();
$this->assertSession()->waitForElementVisible('css', '[name="options[status]"]');
$page->findField('options[status]')->uncheck();
$page->findField('options[sticky]')->check();
$page->findField('options[promote]')->check();
$page->findField('options[revision]')->check();
$locator = '[href="#edit-workflow"] .vertical-tabs__menu-item-summary';
$page->waitFor(10, function () use ($page, $locator) {
$summary = $page->find('css', $locator)->getText();
return strpos('Not published', $summary) !== FALSE;
});
$summary = $page->find('css', $locator)->getText();
$this->assertEquals('Not published, Promoted to front page, Sticky at top of lists, Create new revision', $summary);
}
}

View file

@ -26,7 +26,7 @@ class NodeImportChangeTest extends KernelTestBase {
parent::setUp();
// Set default storage backend.
$this->installConfig(['field', 'node_test_config']);
$this->installConfig(['system', 'field', 'node_test_config']);
}
/**

View file

@ -28,7 +28,7 @@ class NodeImportCreateTest extends KernelTestBase {
$this->installEntitySchema('user');
// Set default storage backend.
$this->installConfig(['field']);
$this->installConfig(['system', 'field']);
}
/**

View file

@ -36,7 +36,7 @@ class MigrateNodeBundleSettingsTest extends MigrateDrupal6TestBase {
$this->executeMigrations([
'd6_node_setting_promote',
'd6_node_setting_status',
'd6_node_setting_sticky'
'd6_node_setting_sticky',
]);
}

View file

@ -42,9 +42,7 @@ class MigrateNodeDeriverTest extends MigrateDrupal6TestBase {
// With content_translation, there should be translation migrations for
// each content type.
$this->enableModules(['language', 'content_translation']);
$migrations = $this->pluginManager->createInstances('d6_node_translation');
$this->assertArrayHasKey('d6_node_translation:story', $migrations,
"Node translation migrations exist after content_translation installed");
$this->assertTrue($this->container->get('plugin.manager.migration')->hasDefinition('d6_node_translation:story'), "Node translation migrations exist after content_translation installed");
}
}

View file

@ -19,7 +19,13 @@ class MigrateNodeTest extends MigrateNodeTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['language', 'content_translation', 'menu_ui'];
public static $modules = [
'language',
'content_translation',
'menu_ui',
// Required for translation migrations.
'migrate_drupal_multilingual',
];
/**
* {@inheritdoc}
@ -94,6 +100,14 @@ class MigrateNodeTest extends MigrateNodeTestBase {
$this->assertCount(2, $node->field_company);
$this->assertSame('Klingon Empire', $node->field_company[0]->entity->label());
$this->assertSame('Romulan Empire', $node->field_company[1]->entity->label());
$this->assertCount(1, $node->field_company_2);
$this->assertSame('Klingon Empire', $node->field_company_2[0]->entity->label());
$this->assertCount(1, $node->field_company_3);
$this->assertSame('Romulan Empire', $node->field_company_3[0]->entity->label());
// Test that user reference field values were migrated.
$this->assertCount(1, $node->field_commander);
$this->assertSame('joe.roe', $node->field_commander[0]->entity->getUsername());
$node = Node::load(2);
$this->assertIdentical('Test title rev 3', $node->getTitle());
@ -219,7 +233,7 @@ class MigrateNodeTest extends MigrateNodeTestBase {
$default_connection = \Drupal::database();
$default_connection->truncate($table_name)->execute();
if ($new_row) {
$hash = $migration->getIdMap()->getSourceIDsHash(['nid' => $new_row['sourceid1']]);
$hash = $migration->getIdMap()->getSourceIdsHash(['nid' => $new_row['sourceid1']]);
$new_row['source_ids_hash'] = $hash;
$default_connection->insert($table_name)
->fields($new_row)

View file

@ -38,7 +38,7 @@ class MigrateNodeTypeTest extends MigrateDrupal6TestBase {
$this->assertIdentical(TRUE, $node_type_page->displaySubmitted());
$this->assertIdentical(FALSE, $node_type_page->isNewRevision());
$this->assertIdentical(DRUPAL_OPTIONAL, $node_type_page->getPreviewMode());
$this->assertIdentical($id_map->lookupDestinationID(['test_page']), ['test_page']);
$this->assertIdentical($id_map->lookupDestinationId(['test_page']), ['test_page']);
// Test we have a body field.
$field = FieldConfig::loadByName('node', 'test_page', 'body');
@ -57,7 +57,7 @@ class MigrateNodeTypeTest extends MigrateDrupal6TestBase {
$this->assertIdentical(TRUE, $node_type_story->displaySubmitted());
$this->assertIdentical(FALSE, $node_type_story->isNewRevision());
$this->assertIdentical(DRUPAL_OPTIONAL, $node_type_story->getPreviewMode());
$this->assertIdentical($id_map->lookupDestinationID(['test_story']), ['test_story']);
$this->assertIdentical($id_map->lookupDestinationId(['test_story']), ['test_story']);
// Test we don't have a body field.
$field = FieldConfig::loadByName('node', 'test_story', 'body');
@ -76,7 +76,7 @@ class MigrateNodeTypeTest extends MigrateDrupal6TestBase {
$this->assertIdentical(TRUE, $node_type_event->displaySubmitted());
$this->assertIdentical(TRUE, $node_type_event->isNewRevision());
$this->assertIdentical(DRUPAL_OPTIONAL, $node_type_event->getPreviewMode());
$this->assertIdentical($id_map->lookupDestinationID(['test_event']), ['test_event']);
$this->assertIdentical($id_map->lookupDestinationId(['test_event']), ['test_event']);
// Test we have a body field.
$field = FieldConfig::loadByName('node', 'test_event', 'body');

View file

@ -29,7 +29,7 @@ class MigrateViewModesTest extends MigrateDrupal6TestBase {
$this->assertIdentical(FALSE, is_null($view_mode), 'Preview view mode loaded.');
$this->assertIdentical('Preview', $view_mode->label(), 'View mode has correct label.');
// Test the ID map.
$this->assertIdentical(['node', 'preview'], $this->getMigration('d6_view_modes')->getIdMap()->lookupDestinationID([1]));
$this->assertIdentical(['node', 'preview'], $this->getMigration('d6_view_modes')->getIdMap()->lookupDestinationId([1]));
}
}

View file

@ -0,0 +1,61 @@
<?php
namespace Drupal\Tests\node\Kernel\Migrate\d6;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests node translation redirections.
*
* @group migrate_drupal
* @group node
*/
class NodeTranslationRedirectTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
public static $modules = [
'content_translation',
'language',
'menu_ui',
// Required for translation migrations.
'migrate_drupal_multilingual',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('node');
$this->installConfig(['node']);
$this->installSchema('node', ['node_access']);
$this->installSchema('system', ['key_value']);
$this->migrateUsers(FALSE);
$this->migrateFields();
$this->executeMigrations([
'language',
'd6_language_types',
'd6_language_negotiation_settings',
'd6_node_settings',
'd6_node',
'd6_node_translation',
]);
}
/**
* Tests that not found node translations are redirected.
*/
public function testNodeTranslationRedirect() {
$kernel = $this->container->get('http_kernel');
$request = Request::create('/node/11');
$response = $kernel->handle($request);
$this->assertSame(301, $response->getStatusCode());
$this->assertSame('/node/10', $response->getTargetUrl());
}
}

View file

@ -11,29 +11,18 @@ use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
*/
class MigrateNodeDeriverTest extends MigrateDrupal7TestBase {
/**
* The migration plugin manager.
*
* @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
*/
protected $pluginManager;
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$this->pluginManager = $this->container->get('plugin.manager.migration');
}
public static $modules = ['node'];
/**
* Test node translation migrations with translation disabled.
*/
public function testNoTranslations() {
// Without content_translation, there should be no translation migrations.
$migrations = $this->pluginManager->createInstances('d7_node_translation');
$this->assertSame([], $migrations,
"No node translation migrations without content_translation");
$migrations = $this->container->get('plugin.manager.migration')->createInstances('d7_node_translation');
$this->assertEmpty($migrations);
}
/**
@ -42,10 +31,8 @@ class MigrateNodeDeriverTest extends MigrateDrupal7TestBase {
public function testTranslations() {
// With content_translation, there should be translation migrations for
// each content type.
$this->enableModules(['language', 'content_translation', 'node', 'filter']);
$migrations = $this->pluginManager->createInstances('d7_node_translation');
$this->assertArrayHasKey('d7_node_translation:article', $migrations,
"Node translation migrations exist after content_translation installed");
$this->enableModules(['language', 'content_translation', 'filter']);
$this->assertTrue($this->container->get('plugin.manager.migration')->hasDefinition('d7_node_translation:article'), "Node translation migrations exist after content_translation installed");
}
}

View file

@ -2,6 +2,8 @@
namespace Drupal\Tests\node\Kernel\Migrate\d7;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
use Drupal\Tests\file\Kernel\Migrate\d7\FileMigrationSetupTrait;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
@ -13,6 +15,8 @@ use Drupal\node\NodeInterface;
*/
class MigrateNodeTest extends MigrateDrupal7TestBase {
use FileMigrationSetupTrait;
/**
* {@inheritdoc}
*/
@ -20,11 +24,15 @@ class MigrateNodeTest extends MigrateDrupal7TestBase {
'content_translation',
'comment',
'datetime',
'file',
'filter',
'forum',
'image',
'language',
'link',
'menu_ui',
// Required for translation migrations.
'migrate_drupal_multilingual',
'node',
'taxonomy',
'telephone',
@ -37,11 +45,14 @@ class MigrateNodeTest extends MigrateDrupal7TestBase {
protected function setUp() {
parent::setUp();
$this->fileMigrationSetup();
$this->installEntitySchema('node');
$this->installEntitySchema('comment');
$this->installEntitySchema('taxonomy_term');
$this->installEntitySchema('file');
$this->installConfig(static::$modules);
$this->installSchema('comment', ['comment_entity_statistics']);
$this->installSchema('forum', ['forum', 'forum_index']);
$this->installSchema('node', ['node_access']);
$this->installSchema('system', ['sequences']);
@ -52,14 +63,30 @@ class MigrateNodeTest extends MigrateDrupal7TestBase {
'd7_node_type',
'd7_language_content_settings',
'd7_comment_type',
'd7_comment_field',
'd7_comment_field_instance',
'd7_taxonomy_vocabulary',
'd7_field',
'd7_field_instance',
'd7_node',
'd7_node_translation',
'd7_entity_translation_settings',
'd7_node_entity_translation',
]);
}
/**
* {@inheritdoc}
*/
protected function getFileMigrationInfo() {
return [
'path' => 'public://sites/default/files/cube.jpeg',
'size' => '3620',
'base_path' => 'public://',
'plugin_id' => 'd7_file',
];
}
/**
* Asserts various aspects of a node.
*
@ -87,18 +114,18 @@ class MigrateNodeTest extends MigrateDrupal7TestBase {
protected function assertEntity($id, $type, $langcode, $title, $uid, $status, $created, $changed, $promoted, $sticky) {
/** @var \Drupal\node\NodeInterface $node */
$node = Node::load($id);
$this->assertTrue($node instanceof NodeInterface);
$this->assertIdentical($type, $node->getType());
$this->assertIdentical($langcode, $node->langcode->value);
$this->assertIdentical($title, $node->getTitle());
$this->assertIdentical($uid, $node->getOwnerId());
$this->assertIdentical($status, $node->isPublished());
$this->assertIdentical($created, $node->getCreatedTime());
$this->assertInstanceOf(NodeInterface::class, $node);
$this->assertEquals($type, $node->getType());
$this->assertEquals($langcode, $node->langcode->value);
$this->assertEquals($title, $node->getTitle());
$this->assertEquals($uid, $node->getOwnerId());
$this->assertEquals($status, $node->isPublished());
$this->assertEquals($created, $node->getCreatedTime());
if (isset($changed)) {
$this->assertIdentical($changed, $node->getChangedTime());
$this->assertEquals($changed, $node->getChangedTime());
}
$this->assertIdentical($promoted, $node->isPromoted());
$this->assertIdentical($sticky, $node->isSticky());
$this->assertEquals($promoted, $node->isPromoted());
$this->assertEquals($sticky, $node->isSticky());
}
/**
@ -117,69 +144,119 @@ class MigrateNodeTest extends MigrateDrupal7TestBase {
*/
protected function assertRevision($id, $title, $uid, $log, $timestamp) {
$revision = \Drupal::entityManager()->getStorage('node')->loadRevision($id);
$this->assertTrue($revision instanceof NodeInterface);
$this->assertIdentical($title, $revision->getTitle());
$this->assertIdentical($uid, $revision->getRevisionUser()->id());
$this->assertIdentical($log, $revision->revision_log->value);
$this->assertIdentical($timestamp, $revision->getRevisionCreationTime());
$this->assertInstanceOf(NodeInterface::class, $revision);
$this->assertEquals($title, $revision->getTitle());
$this->assertEquals($uid, $revision->getRevisionUser()->id());
$this->assertEquals($log, $revision->revision_log->value);
$this->assertEquals($timestamp, $revision->getRevisionCreationTime());
}
/**
* Test node migration from Drupal 7 to 8.
*/
public function testNode() {
$this->assertEntity(1, 'test_content_type', 'en', 'A Node', '2', TRUE, '1421727515', '1441032132', TRUE, FALSE);
$this->assertRevision(1, 'A Node', '1', NULL, '1441032132');
$this->assertEntity(1, 'test_content_type', 'en', 'An English Node', '2', TRUE, '1421727515', '1441032132', TRUE, FALSE);
$this->assertRevision(1, 'An English Node', '1', NULL, '1441032132');
$node = Node::load(1);
$this->assertTrue($node->field_boolean->value);
$this->assertIdentical('99-99-99-99', $node->field_phone->value);
// Use assertEqual() here instead, since SQLite interprets floats strictly.
$this->assertEqual('1', $node->field_float->value);
$this->assertIdentical('5', $node->field_integer->value);
$this->assertIdentical('Some more text', $node->field_text_list[0]->value);
$this->assertIdentical('7', $node->field_integer_list[0]->value);
$this->assertIdentical('qwerty', $node->field_text->value);
$this->assertIdentical('2', $node->field_file->target_id);
$this->assertIdentical('file desc', $node->field_file->description);
$this->assertEquals('99-99-99-99', $node->field_phone->value);
$this->assertEquals('1', $node->field_float->value);
$this->assertEquals('5', $node->field_integer->value);
$this->assertEquals('Some more text', $node->field_text_list[0]->value);
$this->assertEquals('7', $node->field_integer_list[0]->value);
$this->assertEquals('qwerty', $node->field_text->value);
$this->assertEquals('2', $node->field_file->target_id);
$this->assertEquals('file desc', $node->field_file->description);
$this->assertTrue($node->field_file->display);
$this->assertIdentical('1', $node->field_images->target_id);
$this->assertIdentical('alt text', $node->field_images->alt);
$this->assertIdentical('title text', $node->field_images->title);
$this->assertIdentical('93', $node->field_images->width);
$this->assertIdentical('93', $node->field_images->height);
$this->assertIdentical('http://google.com', $node->field_link->uri);
$this->assertIdentical('Click Here', $node->field_link->title);
$this->assertEquals('1', $node->field_images->target_id);
$this->assertEquals('alt text', $node->field_images->alt);
$this->assertEquals('title text', $node->field_images->title);
$this->assertEquals('93', $node->field_images->width);
$this->assertEquals('93', $node->field_images->height);
$this->assertEquals('http://google.com', $node->field_link->uri);
$this->assertEquals('Click Here', $node->field_link->title);
// Test that an email field is migrated.
$this->assertSame('default@example.com', $node->field_email->value);
$this->assertSame('another@example.com', $node->field_email[1]->value);
$this->assertEquals('default@example.com', $node->field_email->value);
$this->assertEquals('another@example.com', $node->field_email[1]->value);
$this->assertEquals(CommentItemInterface::OPEN, $node->comment_node_test_content_type->status);
$this->assertEquals('3.1416', $node->field_float_list[0]->value);
$node = Node::load(2);
$this->assertSame('en', $node->langcode->value);
$this->assertIdentical("...is that it's the absolute best show ever. Trust me, I would know.", $node->body->value);
$this->assertSame('The thing about Deep Space 9', $node->label());
$this->assertIdentical('internal:/', $node->field_link->uri);
$this->assertIdentical('Home', $node->field_link->title);
$this->assertEquals('en', $node->langcode->value);
$this->assertEquals("...is that it's the absolute best show ever. Trust me, I would know.", $node->body->value);
$this->assertEquals('The thing about Deep Space 9', $node->label());
$this->assertEquals('internal:/', $node->field_link->uri);
$this->assertEquals('Home', $node->field_link->title);
$this->assertEquals(CommentItemInterface::OPEN, $node->comment_node_article->status);
$this->assertTrue($node->hasTranslation('is'), "Node 2 has an Icelandic translation");
$translation = $node->getTranslation('is');
$this->assertSame('is', $translation->langcode->value);
$this->assertSame("is - ...is that it's the absolute best show ever. Trust me, I would know.", $translation->body->value);
$this->assertSame('is - The thing about Deep Space 9', $translation->label());
$this->assertSame('internal:/', $translation->field_link->uri);
$this->assertSame('Home', $translation->field_link->title);
$this->assertEquals('is', $translation->langcode->value);
$this->assertEquals("is - ...is that it's the absolute best show ever. Trust me, I would know.", $translation->body->value);
$this->assertEquals('is - The thing about Deep Space 9', $translation->label());
$this->assertEquals('internal:/', $translation->field_link->uri);
$this->assertEquals(CommentItemInterface::OPEN, $translation->comment_node_article->status);
$this->assertEquals('Home', $translation->field_link->title);
// Test that content_translation_source is set.
$manager = $this->container->get('content_translation.manager');
$this->assertSame('en', $manager->getTranslationMetadata($node->getTranslation('is'))->getSource());
$this->assertEquals('en', $manager->getTranslationMetadata($node->getTranslation('is'))->getSource());
// Node 3 is a translation of node 2, and should not be imported separately.
$this->assertNull(Node::load(3), "Node 3 doesn't exist in D8, it was a translation");
// Test that content_translation_source for a source other than English.
$node = Node::load(4);
$this->assertSame('is', $manager->getTranslationMetadata($node->getTranslation('en'))->getSource());
$this->assertEquals('is', $manager->getTranslationMetadata($node->getTranslation('en'))->getSource());
$this->assertEquals(CommentItemInterface::CLOSED, $node->comment_node_article->status);
$translation = $node->getTranslation('en');
$this->assertEquals(CommentItemInterface::CLOSED, $translation->comment_node_article->status);
$node = Node::load(6);
$this->assertEquals(CommentItemInterface::CLOSED, $node->comment_forum->status);
$node = Node::load(7);
$this->assertEquals(CommentItemInterface::OPEN, $node->comment_forum->status);
}
/**
* Test node entity translations migration from Drupal 7 to 8.
*/
public function testNodeEntityTranslations() {
$manager = $this->container->get('content_translation.manager');
// Get the node and its translations.
$node = Node::load(1);
$node_fr = $node->getTranslation('fr');
$node_is = $node->getTranslation('is');
// Test that fields translated with Entity Translation are migrated.
$this->assertSame('An English Node', $node->getTitle());
$this->assertSame('A French Node', $node_fr->getTitle());
$this->assertSame('An Icelandic Node', $node_is->getTitle());
$this->assertSame('5', $node->field_integer->value);
$this->assertSame('6', $node_fr->field_integer->value);
$this->assertSame('7', $node_is->field_integer->value);
// Test that the French translation metadata is correctly migrated.
$metadata_fr = $manager->getTranslationMetadata($node_fr);
$this->assertSame('en', $metadata_fr->getSource());
$this->assertTrue($metadata_fr->isOutdated());
$this->assertSame('2', $node_fr->getOwnerId());
$this->assertSame('1529615802', $node_fr->getCreatedTime());
$this->assertSame('1529615802', $node_fr->getChangedTime());
$this->assertTrue($node_fr->isPublished());
// Test that the Icelandic translation metadata is correctly migrated.
$metadata_is = $manager->getTranslationMetadata($node_is);
$this->assertSame('en', $metadata_is->getSource());
$this->assertFalse($metadata_is->isOutdated());
$this->assertSame('1', $node_is->getOwnerId());
$this->assertSame('1529615813', $node_is->getCreatedTime());
$this->assertSame('1529615813', $node_is->getChangedTime());
$this->assertFalse($node_is->isPublished());
}
}

View file

@ -0,0 +1,63 @@
<?php
namespace Drupal\Tests\node\Kernel\Migrate\d7;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
use Symfony\Component\HttpFoundation\Request;
/**
* Tests node translation redirections.
*
* @group migrate_drupal
* @group node
*/
class NodeTranslationRedirectTest extends MigrateDrupal7TestBase {
/**
* {@inheritdoc}
*/
public static $modules = [
'content_translation',
'language',
'menu_ui',
// Required for translation migrations.
'migrate_drupal_multilingual',
'node',
'text',
];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('node');
$this->installConfig('node');
$this->installSchema('node', ['node_access']);
$this->installSchema('system', ['key_value']);
$this->executeMigrations([
'language',
'd7_language_types',
'd7_language_negotiation_settings',
'd7_user_role',
'd7_user',
'd7_node_type',
'd7_node',
'd7_node_translation',
]);
}
/**
* Tests that not found node translations are redirected.
*/
public function testNodeTranslationRedirect() {
$kernel = $this->container->get('http_kernel');
$request = Request::create('/node/3');
$response = $kernel->handle($request);
$this->assertSame(301, $response->getStatusCode());
$this->assertSame('/node/2', $response->getTargetUrl());
}
}

View file

@ -2,7 +2,7 @@
namespace Drupal\Tests\node\Kernel;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
@ -101,35 +101,35 @@ class NodeFieldAccessTest extends EntityKernelTestBase {
// Checks on view operations.
foreach ($test_users as $account) {
$may_view = $node1->{$field}->access('view', $account);
$this->assertTrue($may_view, SafeMarkup::format('Any user may view the field @name.', ['@name' => $field]));
$this->assertTrue($may_view, new FormattableMarkup('Any user may view the field @name.', ['@name' => $field]));
}
// Checks on edit operations.
$may_update = $node1->{$field}->access('edit', $page_creator_user);
$this->assertFalse($may_update, SafeMarkup::format('Users with permission "edit own page content" is not allowed to the field @name.', ['@name' => $field]));
$this->assertFalse($may_update, new FormattableMarkup('Users with permission "edit own page content" is not allowed to the field @name.', ['@name' => $field]));
$may_update = $node2->{$field}->access('edit', $page_creator_user);
$this->assertFalse($may_update, SafeMarkup::format('Users with permission "edit own page content" is not allowed to the field @name.', ['@name' => $field]));
$this->assertFalse($may_update, new FormattableMarkup('Users with permission "edit own page content" is not allowed to the field @name.', ['@name' => $field]));
$may_update = $node2->{$field}->access('edit', $page_manager_user);
$this->assertFalse($may_update, SafeMarkup::format('Users with permission "edit any page content" is not allowed to the field @name.', ['@name' => $field]));
$this->assertFalse($may_update, new FormattableMarkup('Users with permission "edit any page content" is not allowed to the field @name.', ['@name' => $field]));
$may_update = $node1->{$field}->access('edit', $page_manager_user);
$this->assertFalse($may_update, SafeMarkup::format('Users with permission "edit any page content" is not allowed to the field @name.', ['@name' => $field]));
$this->assertFalse($may_update, new FormattableMarkup('Users with permission "edit any page content" is not allowed to the field @name.', ['@name' => $field]));
$may_update = $node2->{$field}->access('edit', $page_unrelated_user);
$this->assertFalse($may_update, SafeMarkup::format('Users not having permission "edit any page content" is not allowed to the field @name.', ['@name' => $field]));
$this->assertFalse($may_update, new FormattableMarkup('Users not having permission "edit any page content" is not allowed to the field @name.', ['@name' => $field]));
$may_update = $node1->{$field}->access('edit', $content_admin_user) && $node3->status->access('edit', $content_admin_user);
$this->assertTrue($may_update, SafeMarkup::format('Users with permission "administer nodes" may edit @name fields on all nodes.', ['@name' => $field]));
$this->assertTrue($may_update, new FormattableMarkup('Users with permission "administer nodes" may edit @name fields on all nodes.', ['@name' => $field]));
}
foreach ($this->readOnlyFields as $field) {
// Check view operation.
foreach ($test_users as $account) {
$may_view = $node1->{$field}->access('view', $account);
$this->assertTrue($may_view, SafeMarkup::format('Any user may view the field @name.', ['@name' => $field]));
$this->assertTrue($may_view, new FormattableMarkup('Any user may view the field @name.', ['@name' => $field]));
}
// Check edit operation.
foreach ($test_users as $account) {
$may_view = $node1->{$field}->access('edit', $account);
$this->assertFalse($may_view, SafeMarkup::format('No user is not allowed to edit the field @name.', ['@name' => $field]));
$this->assertFalse($may_view, new FormattableMarkup('No user is not allowed to edit the field @name.', ['@name' => $field]));
}
}

View file

@ -23,7 +23,6 @@ class NodeListBuilderTest extends KernelTestBase {
$this->installEntitySchema('node');
}
/**
* Tests that the correct cache contexts are set.
*/

View file

@ -0,0 +1,101 @@
<?php
namespace Drupal\Tests\node\Kernel;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\node\Entity\Node;
use Drupal\node\Entity\NodeType;
use Drupal\user\Entity\User;
/**
* Tests the node view builder.
*
* @group node
*
* @coversDefaultClass \Drupal\node\NodeViewBuilder
*/
class NodeViewBuilderTest extends EntityKernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['node'];
/**
* The node storage.
*
* @var \Drupal\node\NodeStorageInterface
*/
protected $storage;
/**
* The node view builder.
*
* @var \Drupal\Core\Entity\EntityViewBuilderInterface
*/
protected $viewBuilder;
/**
* The renderer.
*
* @var \Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->storage = $this->entityManager->getStorage('node');
$this->viewBuilder = $this->entityManager->getViewBuilder('node');
$this->renderer = $this->container->get('renderer');
$type = NodeType::create([
'type' => 'article',
'name' => 'Article',
]);
$type->save();
$this->installSchema('node', 'node_access');
$this->installConfig(['system', 'node']);
}
/**
* Tests that node links are displayed correctly in pending revisions.
*
* @covers ::buildComponents
* @covers ::renderLinks
* @covers ::buildLinks
*/
public function testPendingRevisionLinks() {
$account = User::create([
'name' => $this->randomString(),
]);
$account->save();
$title = $this->randomMachineName();
$node = Node::create([
'type' => 'article',
'title' => $title,
'uid' => $account->id(),
]);
$node->save();
/** @var \Drupal\node\NodeInterface $pending_revision */
$pending_revision = $this->storage->createRevision($node, FALSE);
$draft_title = $title . ' draft';
$pending_revision->setTitle($draft_title);
$pending_revision->save();
$build = $this->viewBuilder->view($node, 'teaser');
$output = (string) $this->renderer->renderPlain($build);
$this->assertContains("title=\"$title\"", $output);
$build = $this->viewBuilder->view($pending_revision, 'teaser');
$output = (string) $this->renderer->renderPlain($build);
$this->assertContains("title=\"$draft_title\"", $output);
}
}

View file

@ -57,9 +57,139 @@ class NodeTypeTest extends MigrateSqlSourceTestBase {
'orig_type' => 'story',
],
];
$tests[0]['source_data']['variable'] = [
[
'name' => 'comment_anonymous_page',
'value' => 'i:0;',
],
[
'name' => 'comment_anonymous_story',
'value' => 'i:1;',
],
[
'name' => 'comment_default_mode_page',
'value' => 'i:0;',
],
[
'name' => 'comment_default_mode_story',
'value' => 'i:1;',
],
[
'name' => 'comment_default_per_page_page',
'value' => 's:2:"10";',
],
[
'name' => 'comment_default_per_page_story',
'value' => 's:2:"20";',
],
[
'name' => 'comment_form_location_page',
'value' => 'i:0;',
],
[
'name' => 'comment_form_location_story',
'value' => 'i:1;',
],
[
'name' => 'comment_page',
'value' => 's:1:"0";',
],
[
'name' => 'comment_preview_page',
'value' => 's:1:"0";',
],
[
'name' => 'comment_preview_story',
'value' => 's:1:"1";',
],
[
'name' => 'comment_story',
'value' => 's:1:"1";',
],
[
'name' => 'comment_subject_field_page',
'value' => 'i:0;',
],
[
'name' => 'comment_subject_field_story',
'value' => 'i:1;',
],
[
'name' => 'node_options_page',
'value' => 'a:1:{i:0;s:6:"status";}',
],
[
'name' => 'node_options_story',
'value' => 'a:1:{i:0;s:6:"status";}',
],
];
$tests[0]['source_data']['system'] = [
[
'type' => 'module',
'name' => 'comment',
'status' => '1',
],
];
// The expected results.
$tests[0]['expected_data'] = $tests[0]['source_data']['node_type'];
$tests[0]['expected_data'] = [
[
'type' => 'page',
'name' => 'Page',
'module' => 'node',
'description' => 'A <em>page</em>, similar in form to a <em>story</em>, is a simple method for creating and displaying information that rarely changes, such as an "About us" section of a website. By default, a <em>page</em> entry does not allow visitor comments and is not featured on the site\'s initial home page.',
'help' => '',
'title_label' => 'Title',
'has_body' => 1,
'body_label' => 'Body',
'min_word_count' => 0,
'custom' => 1,
'modified' => 0,
'locked' => 0,
'orig_type' => 'page',
'options' => [
'promote' => FALSE,
'sticky' => FALSE,
'status' => TRUE,
'revision' => FALSE,
],
'comment' => 0,
'comment_default_mode' => 0,
'comment_default_per_page' => '10',
'comment_anonymous' => 0,
'comment_subject_field' => 0,
'comment_preview' => 0,
'comment_form_location' => 0,
],
[
'type' => 'story',
'name' => 'Story',
'module' => 'node',
'description' => 'A <em>story</em>, similar in form to a <em>page</em>, is ideal for creating and displaying content that informs or engages website visitors. Press releases, site announcements, and informal blog-like entries may all be created with a <em>story</em> entry. By default, a <em>story</em> entry is automatically featured on the site\'s initial home page, and provides the ability to post comments.',
'help' => '',
'title_label' => 'Title',
'has_body' => 1,
'body_label' => 'Body',
'min_word_count' => 0,
'custom' => 1,
'modified' => 0,
'locked' => 0,
'orig_type' => 'story',
'options' => [
'promote' => FALSE,
'sticky' => FALSE,
'status' => TRUE,
'revision' => FALSE,
],
'comment' => 1,
'comment_default_mode' => 1,
'comment_default_per_page' => '20',
'comment_anonymous' => 1,
'comment_subject_field' => 1,
'comment_preview' => 1,
'comment_form_location' => 1,
],
];
return $tests;
}

View file

@ -0,0 +1,361 @@
<?php
namespace Drupal\Tests\node\Kernel\Plugin\migrate\source\d7;
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
/**
* Tests Drupal 7 node entity translations source plugin.
*
* @covers \Drupal\node\Plugin\migrate\source\d7\NodeEntityTranslation
*
* @group node
*/
class NodeEntityTranslationTest extends MigrateSqlSourceTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['node', 'user', 'migrate_drupal'];
/**
* {@inheritdoc}
*/
public function providerSource() {
$tests = [];
// The source data.
$tests[0]['source_data']['entity_translation'] = [
[
'entity_type' => 'node',
'entity_id' => 2,
'revision_id' => 2,
'language' => 'en',
'source' => '',
'uid' => 1,
'status' => 1,
'translate' => 0,
'created' => 1531343498,
'changed' => 1531343498,
],
[
'entity_type' => 'node',
'entity_id' => 2,
'revision_id' => 2,
'language' => 'fr',
'source' => 'en',
'uid' => 2,
'status' => 1,
'translate' => 1,
'created' => 1531343508,
'changed' => 1531343508,
],
[
'entity_type' => 'node',
'entity_id' => 2,
'revision_id' => 2,
'language' => 'es',
'source' => 'en',
'uid' => 1,
'status' => 0,
'translate' => 0,
'created' => 1531343528,
'changed' => 1531343528,
],
];
$tests[0]['source_data']['field_config'] = [
[
'id' => 1,
'field_name' => 'body',
'type' => 'text_with_summary',
'module' => 'text',
'active' => 1,
'storage_type' => 'field_sql_storage',
'storage_module' => 'field_sql_storage',
'storage_active' => 1,
'locked' => 1,
'data' => 'a:0:{}',
'cardinality' => 1,
'translatable' => 1,
'deleted' => 0,
],
[
'id' => 2,
'field_name' => 'title_field',
'type' => 'text',
'module' => 'text',
'active' => 1,
'storage_type' => 'field_sql_storage',
'storage_module' => 'field_sql_storage',
'storage_active' => 1,
'locked' => 1,
'data' => 'a:0:{}',
'cardinality' => 1,
'translatable' => 1,
'deleted' => 0,
],
];
$tests[0]['source_data']['field_config_instance'] = [
[
'id' => 1,
'field_id' => 1,
'field_name' => 'body',
'entity_type' => 'node',
'bundle' => 'article',
'data' => 'a:0:{}',
'deleted' => 0,
],
[
'id' => 2,
'field_id' => 1,
'field_name' => 'body',
'entity_type' => 'node',
'bundle' => 'page',
'data' => 'a:0:{}',
'deleted' => 0,
],
[
'id' => 3,
'field_id' => 2,
'field_name' => 'title_field',
'entity_type' => 'node',
'bundle' => 'page',
'data' => 'a:0:{}',
'deleted' => 0,
],
];
$tests[0]['source_data']['field_revision_body'] = [
[
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => 0,
'entity_id' => 1,
'revision_id' => 1,
'language' => 'en',
'delta' => 0,
'body_value' => 'Untranslated body',
'body_summary' => 'Untranslated summary',
'body_format' => 'filtered_html',
],
[
'entity_type' => 'node',
'bundle' => 'page',
'deleted' => 0,
'entity_id' => 2,
'revision_id' => 2,
'language' => 'en',
'delta' => 0,
'body_value' => 'English body',
'body_summary' => 'English summary',
'body_format' => 'filtered_html',
],
[
'entity_type' => 'node',
'bundle' => 'page',
'deleted' => 0,
'entity_id' => 2,
'revision_id' => 2,
'language' => 'fr',
'delta' => 0,
'body_value' => 'French body',
'body_summary' => 'French summary',
'body_format' => 'filtered_html',
],
[
'entity_type' => 'node',
'bundle' => 'page',
'deleted' => 0,
'entity_id' => 2,
'revision_id' => 2,
'language' => 'es',
'delta' => 0,
'body_value' => 'Spanish body',
'body_summary' => 'Spanish summary',
'body_format' => 'filtered_html',
],
];
$tests[0]['source_data']['field_revision_title_field'] = [
[
'entity_type' => 'node',
'bundle' => 'page',
'deleted' => '0',
'entity_id' => '2',
'revision_id' => '2',
'language' => 'en',
'delta' => '0',
'title_field_value' => 'English Source',
'title_field_format' => NULL,
],
[
'entity_type' => 'node',
'bundle' => 'page',
'deleted' => '0',
'entity_id' => '2',
'revision_id' => '2',
'language' => 'fr',
'delta' => '0',
'title_field_value' => 'French Translation',
'title_field_format' => NULL,
],
[
'entity_type' => 'node',
'bundle' => 'page',
'deleted' => '0',
'entity_id' => '2',
'revision_id' => '2',
'language' => 'es',
'delta' => '0',
'title_field_value' => 'Spanish Translation',
'title_field_format' => NULL,
],
];
$tests[0]['source_data']['node'] = [
[
'nid' => 1,
'vid' => 1,
'type' => 'article',
'language' => 'en',
'title' => 'Untranslated article',
'uid' => 1,
'status' => 1,
'created' => 1531343456,
'changed' => 1531343456,
'comment' => 2,
'promote' => 1,
'sticky' => 0,
'tnid' => 0,
'translate' => 0,
],
[
'nid' => 2,
'vid' => 2,
'type' => 'page',
'language' => 'en',
'title' => 'Translated page',
'uid' => 1,
'status' => 1,
'created' => 1531343528,
'changed' => 1531343528,
'comment' => 1,
'promote' => 0,
'sticky' => 0,
'tnid' => 0,
'translate' => 0,
],
];
$tests[0]['source_data']['node_revision'] = [
[
'nid' => 1,
'vid' => 1,
'uid' => 1,
'title' => 'Untranslated article',
'log' => '',
'timestamp' => 1531343456,
'status' => 1,
'comment' => 2,
'promote' => 1,
'sticky' => 0,
],
[
'nid' => 2,
'vid' => 2,
'uid' => 1,
'title' => 'Translated page',
'log' => '',
'timestamp' => 1531343528,
'status' => 1,
'comment' => 1,
'promote' => 0,
'sticky' => 0,
],
];
$tests[0]['source_data']['system'] = [
[
'name' => 'title',
'type' => 'module',
'status' => 1,
],
];
// The expected results.
$tests[0]['expected_data'] = [
[
'entity_type' => 'node',
'entity_id' => 2,
'revision_id' => 2,
'language' => 'fr',
'source' => 'en',
'uid' => 2,
'status' => 1,
'translate' => 1,
'created' => 1531343508,
'changed' => 1531343508,
'type' => 'page',
'title' => 'French Translation',
'promote' => 0,
'sticky' => 0,
'log' => '',
'timestamp' => 1531343528,
'revision_uid' => 1,
'body' => [
[
'value' => 'French body',
'summary' => 'French summary',
'format' => 'filtered_html',
],
],
],
[
'entity_type' => 'node',
'entity_id' => 2,
'revision_id' => 2,
'language' => 'es',
'source' => 'en',
'uid' => 1,
'status' => 0,
'translate' => 0,
'created' => 1531343528,
'changed' => 1531343528,
'type' => 'page',
'title' => 'Spanish Translation',
'promote' => 0,
'sticky' => 0,
'log' => '',
'timestamp' => 1531343528,
'revision_uid' => 1,
'body' => [
[
'value' => 'Spanish body',
'summary' => 'Spanish summary',
'format' => 'filtered_html',
],
],
],
];
// Do an automatic count.
$tests[0]['expected_count'] = NULL;
// Set up source plugin configuration.
$tests[0]['configuration'] = [
'node_type' => 'page',
];
// The source data.
$tests[1]['source_data'] = $tests[0]['source_data'];
// The expected results.
$tests[1]['expected_data'] = [];
// Do an automatic count.
$tests[1]['expected_count'] = NULL;
// Set up source plugin configuration.
$tests[1]['configuration'] = [
'node_type' => 'article',
];
return $tests;
}
}

View file

@ -170,6 +170,16 @@ class NodeTest extends MigrateSqlSourceTestBase {
'sticky' => 0,
],
];
$tests[0]['source_data']['field_config'] = [
[
'id' => '2',
'translatable' => '0',
],
[
'id' => '3',
'translatable' => '1',
],
];
$tests[0]['source_data']['field_config_instance'] = [
[
'id' => '2',
@ -189,6 +199,15 @@ class NodeTest extends MigrateSqlSourceTestBase {
'data' => 'a:0:{}',
'deleted' => '0',
],
[
'id' => '4',
'field_id' => '3',
'field_name' => 'title_field',
'entity_type' => 'node',
'bundle' => 'article',
'data' => 'a:0:{}',
'deleted' => '0',
],
];
$tests[0]['source_data']['field_revision_body'] = [
[
@ -252,6 +271,48 @@ class NodeTest extends MigrateSqlSourceTestBase {
'body_format' => 'filtered_html',
],
];
$tests[0]['source_data']['field_revision_title_field'] = [
[
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '5',
'revision_id' => '5',
'language' => 'en',
'delta' => '0',
'title_field_value' => 'node title 5 (title_field)',
'title_field_format' => NULL,
],
[
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '6',
'revision_id' => '6',
'language' => 'en',
'delta' => '0',
'title_field_value' => 'node title 5 (title_field)',
'title_field_format' => NULL,
],
[
'entity_type' => 'node',
'bundle' => 'article',
'deleted' => '0',
'entity_id' => '7',
'revision_id' => '7',
'language' => 'en',
'delta' => '0',
'title_field_value' => 'node title 5 (title_field)',
'title_field_format' => NULL,
],
];
$tests[0]['source_data']['system'] = [
[
'name' => 'title',
'type' => 'module',
'status' => 1,
],
];
// The expected results.
$tests[0]['expected_data'] = [
@ -312,7 +373,7 @@ class NodeTest extends MigrateSqlSourceTestBase {
'vid' => 5,
'type' => 'article',
'language' => 'en',
'title' => 'node title 5',
'title' => 'node title 5 (title_field)',
'node_uid' => 1,
'revision_uid' => 2,
'status' => 1,
@ -338,7 +399,7 @@ class NodeTest extends MigrateSqlSourceTestBase {
'vid' => 6,
'type' => 'article',
'language' => 'en',
'title' => 'node title 5',
'title' => 'node title 5 (title_field)',
'node_uid' => 1,
'revision_uid' => 1,
'status' => 1,
@ -361,6 +422,169 @@ class NodeTest extends MigrateSqlSourceTestBase {
],
];
// The source data with a correct 'entity_translation' table.
$tests[1]['source_data']['entity_translation'] = [
[
'entity_type' => 'node',
'entity_id' => 1,
'revision_id' => 1,
'language' => 'en',
'source' => '',
'uid' => 1,
'status' => 1,
'translate' => 0,
'created' => 1279051598,
'changed' => 1279051598,
],
[
'entity_type' => 'node',
'entity_id' => 1,
'revision_id' => 1,
'language' => 'fr',
'source' => 'en',
'uid' => 1,
'status' => 1,
'translate' => 0,
'created' => 1279051598,
'changed' => 1279051598,
],
];
$tests[1]['source_data']['field_config'] = [
[
'id' => '1',
'translatable' => '1',
],
];
$tests[1]['source_data']['field_config_instance'] = [
[
'id' => '1',
'field_id' => '1',
'field_name' => 'body',
'entity_type' => 'node',
'bundle' => 'page',
'data' => 'a:0:{}',
'deleted' => '0',
],
];
$tests[1]['source_data']['field_revision_body'] = [
[
'entity_type' => 'node',
'bundle' => 'page',
'deleted' => '0',
'entity_id' => '1',
'revision_id' => '1',
'language' => 'en',
'delta' => '0',
'body_value' => 'English body',
'body_summary' => '',
'body_format' => 'filtered_html',
],
[
'entity_type' => 'node',
'bundle' => 'page',
'deleted' => '0',
'entity_id' => '1',
'revision_id' => '1',
'language' => 'fr',
'delta' => '0',
'body_value' => 'French body',
'body_summary' => '',
'body_format' => 'filtered_html',
],
];
$tests[1]['source_data']['node'] = [
[
'nid' => 1,
'vid' => 1,
'type' => 'page',
'language' => 'en',
'title' => 'Node Title',
'uid' => 1,
'status' => 1,
'created' => 1279051598,
'changed' => 1279051598,
'comment' => 2,
'promote' => 1,
'sticky' => 0,
'tnid' => 0,
'translate' => 0,
],
];
$tests[1]['source_data']['node_revision'] = [
[
'nid' => 1,
'vid' => 1,
'uid' => 1,
'title' => 'Node Title',
'log' => '',
'timestamp' => 1279051598,
'status' => 1,
'comment' => 2,
'promote' => 1,
'sticky' => 0,
],
];
$tests[1]['source_data']['variable'] = [
[
'name' => 'entity_translation_entity_types',
'value' => 'a:4:{s:7:"comment";i:0;s:4:"node";s:4:"node";s:13:"taxonomy_term";i:0;s:4:"user";i:0;}',
],
[
'name' => 'language_content_type_page',
'value' => 's:1:"4";',
],
];
// The expected results with a correct 'entity_translation' table.
// entity_translation table.
$tests[1]['expected_data'] = [
[
'nid' => 1,
'vid' => 1,
'type' => 'page',
'language' => 'en',
'title' => 'Node Title',
'node_uid' => 1,
'revision_uid' => 1,
'status' => 1,
'created' => 1279051598,
'changed' => 1279051598,
'comment' => 2,
'promote' => 1,
'sticky' => 0,
'tnid' => 1,
'translate' => 0,
'log' => '',
'timestamp' => 1279051598,
'body' => [
[
'value' => 'English body',
'summary' => '',
'format' => 'filtered_html',
],
],
],
];
// Repeat the previous test with an incorrect 'entity_translation' table
// where the row with the empty 'source' property is missing.
$tests[2]['source_data'] = $tests[1]['source_data'];
$tests[2]['source_data']['entity_translation'] = [
[
'entity_type' => 'node',
'entity_id' => 1,
'revision_id' => 1,
'language' => 'fr',
'source' => 'en',
'uid' => 1,
'status' => 1,
'translate' => 0,
'created' => 1279051598,
'changed' => 1279051598,
],
];
$tests[2]['expected_data'] = $tests[1]['expected_data'];
return $tests;
}

View file

@ -31,7 +31,7 @@ class NodeTranslationTest extends NodeTest {
'vid' => 7,
'type' => 'article',
'language' => 'fr',
'title' => 'fr - node title 5',
'title' => 'node title 5 (title_field)',
'node_uid' => 1,
'revision_uid' => 1,
'status' => 1,

View file

@ -54,6 +54,62 @@ class NodeTypeTest extends MigrateSqlSourceTestBase {
],
];
$tests[0]['source_data']['variable'] = [
[
'name' => 'comment_anonymous_page',
'value' => 'i:0;',
],
[
'name' => 'comment_anonymous_story',
'value' => 'i:1;',
],
[
'name' => 'comment_default_mode_page',
'value' => 'i:0;',
],
[
'name' => 'comment_default_mode_story',
'value' => 'i:1;',
],
[
'name' => 'comment_default_per_page_page',
'value' => 's:2:"10";',
],
[
'name' => 'comment_default_per_page_story',
'value' => 's:2:"20";',
],
[
'name' => 'comment_form_location_page',
'value' => 'i:0;',
],
[
'name' => 'comment_form_location_story',
'value' => 'i:1;',
],
[
'name' => 'comment_page',
'value' => 's:1:"0";',
],
[
'name' => 'comment_preview_page',
'value' => 's:1:"0";',
],
[
'name' => 'comment_preview_story',
'value' => 's:1:"1";',
],
[
'name' => 'comment_story',
'value' => 's:1:"1";',
],
[
'name' => 'comment_subject_field_page',
'value' => 'i:0;',
],
[
'name' => 'comment_subject_field_story',
'value' => 'i:1;',
],
[
'name' => 'node_options_page',
'value' => 'a:1:{i:0;s:6:"status";}',
@ -77,9 +133,78 @@ class NodeTypeTest extends MigrateSqlSourceTestBase {
'data' => 'a:1:{s:5:"label";s:4:"Body";}',
],
];
$tests[0]['source_data']['system'] = [
[
'type' => 'module',
'name' => 'comment',
'status' => '1',
],
[
'type' => 'module',
'name' => 'field',
'status' => '1',
],
];
// The expected results.
$tests[0]['expected_data'] = $tests[0]['source_data']['node_type'];
$tests[0]['expected_data'] = [
[
'type' => 'page',
'name' => 'Page',
'base' => 'node',
'description' => 'A <em>page</em>, similar in form to a <em>story</em>, is a simple method for creating and displaying information that rarely changes, such as an "About us" section of a website. By default, a <em>page</em> entry does not allow visitor comments and is not featured on the site\'s initial home page.',
'help' => '',
'title_label' => 'Title',
'custom' => 1,
'modified' => 0,
'locked' => 0,
'disabled' => 0,
'orig_type' => 'page',
'options' => [
'promote' => FALSE,
'sticky' => FALSE,
'status' => TRUE,
'revision' => FALSE,
],
'create_body' => TRUE,
'body_label' => 'Body',
'comment' => 0,
'comment_default_mode' => 0,
'comment_default_per_page' => '10',
'comment_anonymous' => 0,
'comment_subject_field' => 0,
'comment_preview' => 0,
'comment_form_location' => 0,
],
[
'type' => 'story',
'name' => 'Story',
'base' => 'node',
'description' => 'A <em>story</em>, similar in form to a <em>page</em>, is ideal for creating and displaying content that informs or engages website visitors. Press releases, site announcements, and informal blog-like entries may all be created with a <em>story</em> entry. By default, a <em>story</em> entry is automatically featured on the site\'s initial home page, and provides the ability to post comments.',
'help' => '',
'title_label' => 'Title',
'custom' => 1,
'modified' => 0,
'locked' => 0,
'disabled' => 0,
'orig_type' => 'story',
'options' => [
'promote' => FALSE,
'sticky' => FALSE,
'status' => TRUE,
'revision' => FALSE,
],
'create_body' => TRUE,
'body_label' => 'Body',
'comment' => 1,
'comment_default_mode' => 1,
'comment_default_per_page' => '20',
'comment_anonymous' => 1,
'comment_subject_field' => 1,
'comment_preview' => 1,
'comment_form_location' => 1,
],
];
return $tests;
}

View file

@ -2,7 +2,6 @@
namespace Drupal\Tests\node\Kernel;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Datetime\Entity\DateFormat;
use Drupal\KernelTests\KernelTestBase;
use Drupal\node\Entity\Node;
@ -72,9 +71,6 @@ class SummaryLengthTest extends KernelTestBase {
'label' => 'Fallback',
'pattern' => 'Y-m-d',
])->save();
// Enable multibyte support.
Unicode::setStatus(Unicode::STATUS_MULTIBYTE);
}
/**

View file

@ -0,0 +1,54 @@
<?php
namespace Drupal\Tests\node\Traits;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\node\Entity\NodeType;
use PHPUnit\Framework\TestCase;
/**
* Provides methods to create content type from given values.
*
* This trait is meant to be used only by test classes.
*/
trait ContentTypeCreationTrait {
/**
* Creates a custom content type based on default settings.
*
* @param array $values
* An array of settings to change from the defaults.
* Example: 'type' => 'foo'.
*
* @return \Drupal\node\Entity\NodeType
* Created content type.
*/
protected function createContentType(array $values = []) {
// Find a non-existent random type name.
if (!isset($values['type'])) {
do {
$id = strtolower($this->randomMachineName(8));
} while (NodeType::load($id));
}
else {
$id = $values['type'];
}
$values += [
'type' => $id,
'name' => $id,
];
$type = NodeType::create($values);
$status = $type->save();
node_add_body_field($type);
if ($this instanceof TestCase) {
$this->assertSame($status, SAVED_NEW, (new FormattableMarkup('Created content type %type.', ['%type' => $type->id()]))->__toString());
}
else {
$this->assertEqual($status, SAVED_NEW, (new FormattableMarkup('Created content type %type.', ['%type' => $type->id()]))->__toString());
}
return $type;
}
}

View file

@ -0,0 +1,86 @@
<?php
namespace Drupal\Tests\node\Traits;
use Drupal\node\Entity\Node;
/**
* Provides methods to create node based on default settings.
*
* This trait is meant to be used only by test classes.
*/
trait NodeCreationTrait {
/**
* Get a node from the database based on its title.
*
* @param string|\Drupal\Component\Render\MarkupInterface $title
* A node title, usually generated by $this->randomMachineName().
* @param $reset
* (optional) Whether to reset the entity cache.
*
* @return \Drupal\node\NodeInterface
* A node entity matching $title.
*/
public function getNodeByTitle($title, $reset = FALSE) {
if ($reset) {
\Drupal::entityTypeManager()->getStorage('node')->resetCache();
}
// Cast MarkupInterface objects to string.
$title = (string) $title;
$nodes = \Drupal::entityTypeManager()
->getStorage('node')
->loadByProperties(['title' => $title]);
// Load the first node returned from the database.
$returned_node = reset($nodes);
return $returned_node;
}
/**
* Creates a node based on default settings.
*
* @param array $settings
* (optional) An associative array of settings for the node, as used in
* entity_create(). Override the defaults by specifying the key and value
* in the array, for example:
* @code
* $this->drupalCreateNode(array(
* 'title' => t('Hello, world!'),
* 'type' => 'article',
* ));
* @endcode
* The following defaults are provided:
* - body: Random string using the default filter format:
* @code
* $settings['body'][0] = array(
* 'value' => $this->randomMachineName(32),
* 'format' => filter_default_format(),
* );
* @endcode
* - title: Random string.
* - type: 'page'.
* - uid: The currently logged in user, or anonymous.
*
* @return \Drupal\node\NodeInterface
* The created node entity.
*/
protected function createNode(array $settings = []) {
// Populate defaults array.
$settings += [
'body' => [
[
'value' => $this->randomMachineName(32),
'format' => filter_default_format(),
],
],
'title' => $this->randomMachineName(8),
'type' => 'page',
'uid' => \Drupal::currentUser()->id(),
];
$node = Node::create($settings);
$node->save();
return $node;
}
}

View file

@ -54,6 +54,8 @@ class NodeBulkFormTest extends UnitTestCase {
$language_manager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
$messenger = $this->getMock('Drupal\Core\Messenger\MessengerInterface');
$views_data = $this->getMockBuilder('Drupal\views\ViewsData')
->disableOriginalConstructor()
->getMock();
@ -84,7 +86,7 @@ class NodeBulkFormTest extends UnitTestCase {
$definition['title'] = '';
$options = [];
$node_bulk_form = new NodeBulkForm([], 'node_bulk_form', $definition, $entity_manager, $language_manager);
$node_bulk_form = new NodeBulkForm([], 'node_bulk_form', $definition, $entity_manager, $language_manager, $messenger);
$node_bulk_form->init($executable, $display, $options);
$this->assertAttributeEquals(array_slice($actions, 0, -1, TRUE), 'actions', $node_bulk_form);