CommentNonNodeTest.php 19.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
<?php

/**
 * @file
 * Contains \Drupal\comment\Tests\CommentNonNodeTest.
 */

namespace Drupal\comment\Tests;

use Drupal\comment\CommentInterface;
11
use Drupal\comment\Entity\Comment;
12
use Drupal\comment\Entity\CommentType;
13
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
14
use Drupal\entity_test\Entity\EntityTest;
15
use Drupal\field\Entity\FieldConfig;
16
use Drupal\field\Entity\FieldStorageConfig;
17
use Drupal\field_ui\Tests\FieldUiTestTrait;
18 19
use Drupal\simpletest\WebTestBase;
use Drupal\Core\Entity\EntityInterface;
20
use Drupal\user\RoleInterface;
21 22

/**
23 24 25
 * Tests commenting on a test entity.
 *
 * @group comment
26 27 28
 */
class CommentNonNodeTest extends WebTestBase {

29
  use FieldUiTestTrait;
30
  use CommentTestTrait;
31

32
  public static $modules = array('comment', 'user', 'field_ui', 'entity_test', 'block');
33 34 35 36 37 38

  /**
   * An administrative user with permission to configure comment settings.
   *
   * @var \Drupal\user\UserInterface
   */
39
  protected $adminUser;
40

41 42 43 44 45 46 47
  /**
   * The entity to use within tests.
   *
   * @var \Drupal\entity_test\Entity\EntityTest
   */
  protected $entity;

48 49 50
  /**
   * {@inheritdoc}
   */
51
  protected function setUp() {
52
    parent::setUp();
53
    $this->drupalPlaceBlock('system_breadcrumb_block');
54
    $this->drupalPlaceBlock('page_title_block');
55

56 57
    // Create a bundle for entity_test.
    entity_test_create_bundle('entity_test', 'Entity Test', 'entity_test');
58
    CommentType::create(array(
59 60 61 62 63
      'id' => 'comment',
      'label' => 'Comment settings',
      'description' => 'Comment settings',
      'target_entity_type_id' => 'entity_test',
    ))->save();
64
    // Create comment field on entity_test bundle.
65
    $this->addDefaultCommentField('entity_test', 'entity_test');
66

67 68
    // Verify that bundles are defined correctly.
    $bundles = \Drupal::entityManager()->getBundleInfo('comment');
69
    $this->assertEqual($bundles['comment']['label'], 'Comment settings');
70

71
    // Create test user.
72
    $this->adminUser = $this->drupalCreateUser(array(
73 74 75 76 77 78 79 80 81
      'administer comments',
      'skip comment approval',
      'post comments',
      'access comments',
      'view test entity',
      'administer entity_test content',
    ));

    // Enable anonymous and authenticated user comments.
82
    user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, array(
83 84 85 86
      'access comments',
      'post comments',
      'skip comment approval',
    ));
87
    user_role_grant_permissions(RoleInterface::AUTHENTICATED_ID, array(
88 89 90 91 92 93
      'access comments',
      'post comments',
      'skip comment approval',
    ));

    // Create a test entity.
94
    $random_label = $this->randomMachineName();
95
    $data = array('type' => 'entity_test', 'name' => $random_label);
96
    $this->entity = EntityTest::create($data);
97 98 99 100 101 102 103 104
    $this->entity->save();
  }

  /**
   * Posts a comment.
   *
   * @param \Drupal\Core\Entity\EntityInterface|null $entity
   *   Entity to post comment on or NULL to post to the previously loaded page.
105
   * @param string $comment
106
   *   Comment body.
107
   * @param string $subject
108
   *   Comment subject.
109
   * @param mixed $contact
110 111
   *   Set to NULL for no contact info, TRUE to ignore success checking, and
   *   array of values to set contact info.
112 113 114
   *
   * @return \Drupal\comment\CommentInterface
   *   The new comment entity.
115 116 117 118 119
   */
  function postComment(EntityInterface $entity, $comment, $subject = '', $contact = NULL) {
    $edit = array();
    $edit['comment_body[0][value]'] = $comment;

120 121
    $field = FieldConfig::loadByName('entity_test', 'entity_test', 'comment');
    $preview_mode = $field->getSetting('preview');
122 123 124

    // Must get the page before we test for fields.
    if ($entity !== NULL) {
125
      $this->drupalGet('comment/reply/entity_test/' . $entity->id() . '/comment');
126 127
    }

128 129 130 131
    // Determine the visibility of subject form field.
    if (entity_get_form_display('comment', 'comment', 'default')->getComponent('subject')) {
      // Subject input allowed.
      $edit['subject[0][value]'] = $subject;
132 133
    }
    else {
134
      $this->assertNoFieldByName('subject[0][value]', '', 'Subject field not found.');
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
    }

    if ($contact !== NULL && is_array($contact)) {
      $edit += $contact;
    }
    switch ($preview_mode) {
      case DRUPAL_REQUIRED:
        // Preview required so no save button should be found.
        $this->assertNoFieldByName('op', t('Save'), 'Save button not found.');
        $this->drupalPostForm(NULL, $edit, t('Preview'));
        // Don't break here so that we can test post-preview field presence and
        // function below.
      case DRUPAL_OPTIONAL:
        $this->assertFieldByName('op', t('Preview'), 'Preview button found.');
        $this->assertFieldByName('op', t('Save'), 'Save button found.');
        $this->drupalPostForm(NULL, $edit, t('Save'));
        break;

      case DRUPAL_DISABLED:
        $this->assertNoFieldByName('op', t('Preview'), 'Preview button not found.');
        $this->assertFieldByName('op', t('Save'), 'Save button found.');
        $this->drupalPostForm(NULL, $edit, t('Save'));
        break;
    }
    $match = array();
    // Get comment ID
    preg_match('/#comment-([0-9]+)/', $this->getURL(), $match);

    // Get comment.
    if ($contact !== TRUE) { // If true then attempting to find error message.
      if ($subject) {
        $this->assertText($subject, 'Comment subject posted.');
      }
      $this->assertText($comment, 'Comment body posted.');
      $this->assertTrue((!empty($match) && !empty($match[1])), 'Comment ID found.');
    }

    if (isset($match[1])) {
173
      return Comment::load($match[1]);
174 175 176 177 178 179 180 181
    }
  }

  /**
   * Checks current page for specified comment.
   *
   * @param \Drupal\comment\CommentInterface $comment
   *   The comment object.
182
   * @param bool $reply
183 184
   *   Boolean indicating whether the comment is a reply to another comment.
   *
185
   * @return bool
186 187 188 189 190
   *   Boolean indicating whether the comment was found.
   */
  function commentExists(CommentInterface $comment = NULL, $reply = FALSE) {
    if ($comment) {
      $regex = '/' . ($reply ? '<div class="indented">(.*?)' : '');
191 192 193
      $regex .= '<a id="comment-' . $comment->id() . '"(.*?)';
      $regex .= $comment->getSubject() . '(.*?)';
      $regex .= $comment->comment_body->value . '(.*?)';
194 195
      $regex .= '/s';

196
      return (boolean) preg_match($regex, $this->getRawContent());
197 198 199 200 201 202 203 204 205
    }
    else {
      return FALSE;
    }
  }

  /**
   * Checks whether the commenter's contact information is displayed.
   *
206
   * @return bool
207 208 209
   *   Contact info is available.
   */
  function commentContactInfoAvailable() {
210
    return preg_match('/(input).*?(name="name").*?(input).*?(name="mail").*?(input).*?(name="homepage")/s', $this->getRawContent());
211 212 213 214 215 216 217 218 219
  }

  /**
   * Performs the specified operation on the specified comment.
   *
   * @param object $comment
   *   Comment to perform operation on.
   * @param string $operation
   *   Operation to perform.
220
   * @param bool $approval
221 222 223 224 225 226 227 228 229 230
   *   Operation is found on approval page.
   */
  function performCommentOperation($comment, $operation, $approval = FALSE) {
    $edit = array();
    $edit['operation'] = $operation;
    $edit['comments[' . $comment->id() . ']'] = TRUE;
    $this->drupalPostForm('admin/content/comment' . ($approval ? '/approval' : ''), $edit, t('Update'));

    if ($operation == 'delete') {
      $this->drupalPostForm(NULL, array(), t('Delete comments'));
231
      $this->assertRaw(\Drupal::translation()->formatPlural(1, 'Deleted 1 comment.', 'Deleted @count comments.'), format_string('Operation "@operation" was performed on comment.', array('@operation' => $operation)));
232 233 234 235 236 237 238 239 240 241 242 243
    }
    else {
      $this->assertText(t('The update has been performed.'), format_string('Operation "@operation" was performed on comment.', array('@operation' => $operation)));
    }
  }

  /**
   * Gets the comment ID for an unapproved comment.
   *
   * @param string $subject
   *   Comment subject to find.
   *
244
   * @return int
245 246 247 248
   *   Comment ID.
   */
  function getUnapprovedComment($subject) {
    $this->drupalGet('admin/content/comment/approval');
249
    preg_match('/href="(.*?)#comment-([^"]+)"(.*?)>(' . $subject . ')/', $this->getRawContent(), $match);
250 251 252 253 254 255 256 257 258

    return $match[2];
  }

  /**
   * Tests anonymous comment functionality.
   */
  function testCommentFunctionality() {
    $limited_user = $this->drupalCreateUser(array(
259
      'administer entity_test fields'
260 261 262
    ));
    $this->drupalLogin($limited_user);
    // Test that default field exists.
263
    $this->drupalGet('entity_test/structure/entity_test/fields');
264
    $this->assertText(t('Comments'));
265
    $this->assertLinkByHref('entity_test/structure/entity_test/fields/entity_test.entity_test.comment');
266
    // Test widget hidden option is not visible when there's no comments.
267 268
    $this->drupalGet('entity_test/structure/entity_test/fields/entity_test.entity_test.comment');
    $this->assertResponse(200);
269
    $this->assertNoField('edit-default-value-input-comment-und-0-status-0');
270 271 272
    // Test that field to change cardinality is not available.
    $this->drupalGet('entity_test/structure/entity_test/fields/entity_test.entity_test.comment/storage');
    $this->assertResponse(200);
273 274
    $this->assertNoField('cardinality_number');
    $this->assertNoField('cardinality');
275

276
    $this->drupalLogin($this->adminUser);
277

278 279 280 281 282
    // Test breadcrumb on comment add page.
    $this->drupalGet('comment/reply/entity_test/' . $this->entity->id() . '/comment');
    $xpath = '//nav[@class="breadcrumb"]/ol/li[last()]/a';
    $this->assertEqual(current($this->xpath($xpath)), $this->entity->label(), 'Last breadcrumb item is equal to node title on comment reply page.');

283
    // Post a comment.
284
    /** @var \Drupal\comment\CommentInterface $comment1 */
285
    $comment1 = $this->postComment($this->entity, $this->randomMachineName(), $this->randomMachineName());
286 287
    $this->assertTrue($this->commentExists($comment1), 'Comment on test entity exists.');

288 289 290 291 292 293 294 295 296 297 298 299 300 301
    // Test breadcrumb on comment reply page.
    $this->drupalGet('comment/reply/entity_test/' . $this->entity->id() . '/comment/' . $comment1->id());
    $xpath = '//nav[@class="breadcrumb"]/ol/li[last()]/a';
    $this->assertEqual(current($this->xpath($xpath)), $comment1->getSubject(), 'Last breadcrumb item is equal to comment title on comment reply page.');

    // Test breadcrumb on comment edit page.
    $this->drupalGet('comment/' . $comment1->id() . '/edit');
    $xpath = '//nav[@class="breadcrumb"]/ol/li[last()]/a';
    $this->assertEqual(current($this->xpath($xpath)), $comment1->getSubject(), 'Last breadcrumb item is equal to comment subject on edit page.');

    // Test breadcrumb on comment delete page.
    $this->drupalGet('comment/' . $comment1->id() . '/delete');
    $xpath = '//nav[@class="breadcrumb"]/ol/li[last()]/a';
    $this->assertEqual(current($this->xpath($xpath)), $comment1->getSubject(), 'Last breadcrumb item is equal to comment subject on delete confirm page.');
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318

    // Unpublish the comment.
    $this->performCommentOperation($comment1, 'unpublish');
    $this->drupalGet('admin/content/comment/approval');
    $this->assertRaw('comments[' . $comment1->id() . ']', 'Comment was unpublished.');

    // Publish the comment.
    $this->performCommentOperation($comment1, 'publish', TRUE);
    $this->drupalGet('admin/content/comment');
    $this->assertRaw('comments[' . $comment1->id() . ']', 'Comment was published.');

    // Delete the comment.
    $this->performCommentOperation($comment1, 'delete');
    $this->drupalGet('admin/content/comment');
    $this->assertNoRaw('comments[' . $comment1->id() . ']', 'Comment was deleted.');

    // Post another comment.
319
    $comment1 = $this->postComment($this->entity, $this->randomMachineName(), $this->randomMachineName());
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
    $this->assertTrue($this->commentExists($comment1), 'Comment on test entity exists.');

    // Check that the comment was found.
    $this->drupalGet('admin/content/comment');
    $this->assertRaw('comments[' . $comment1->id() . ']', 'Comment was published.');

    // Check that entity access applies to administrative page.
    $this->assertText($this->entity->label(), 'Name of commented account found.');
    $limited_user = $this->drupalCreateUser(array(
      'administer comments',
    ));
    $this->drupalLogin($limited_user);
    $this->drupalGet('admin/content/comment');
    $this->assertNoText($this->entity->label(), 'No commented account name found.');

    $this->drupalLogout();

    // Deny anonymous users access to comments.
338
    user_role_change_permissions(RoleInterface::ANONYMOUS_ID, array(
339 340 341 342 343 344 345
      'access comments' => FALSE,
      'post comments' => FALSE,
      'skip comment approval' => FALSE,
      'view test entity' => TRUE,
    ));

    // Attempt to view comments while disallowed.
346
    $this->drupalGet('entity-test/' . $this->entity->id());
347 348 349 350
    $this->assertNoPattern('@<h2[^>]*>Comments</h2>@', 'Comments were not displayed.');
    $this->assertNoLink('Add new comment', 'Link to add comment was found.');

    // Attempt to view test entity comment form while disallowed.
351
    $this->drupalGet('comment/reply/entity_test/' . $this->entity->id() . '/comment');
352
    $this->assertResponse(403);
353
    $this->assertNoFieldByName('subject[0][value]', '', 'Subject field not found.');
354 355
    $this->assertNoFieldByName('comment_body[0][value]', '', 'Comment field not found.');

356
    user_role_change_permissions(RoleInterface::ANONYMOUS_ID, array(
357 358 359 360 361
      'access comments' => TRUE,
      'post comments' => FALSE,
      'view test entity' => TRUE,
      'skip comment approval' => FALSE,
    ));
362
    $this->drupalGet('entity_test/' . $this->entity->id());
363 364 365
    $this->assertPattern('@<h2[^>]*>Comments</h2>@', 'Comments were displayed.');
    $this->assertLink('Log in', 0, 'Link to log in was found.');
    $this->assertLink('register', 0, 'Link to register was found.');
366
    $this->assertNoFieldByName('subject[0][value]', '', 'Subject field not found.');
367 368 369 370 371
    $this->assertNoFieldByName('comment_body[0][value]', '', 'Comment field not found.');

    // Test the combination of anonymous users being able to post, but not view
    // comments, to ensure that access to post comments doesn't grant access to
    // view them.
372
    user_role_change_permissions(RoleInterface::ANONYMOUS_ID, array(
373 374 375 376 377
      'access comments' => FALSE,
      'post comments' => TRUE,
      'skip comment approval' => TRUE,
      'view test entity' => TRUE,
    ));
378
    $this->drupalGet('entity_test/' . $this->entity->id());
379
    $this->assertNoPattern('@<h2[^>]*>Comments</h2>@', 'Comments were not displayed.');
380
    $this->assertFieldByName('subject[0][value]', '', 'Subject field found.');
381 382
    $this->assertFieldByName('comment_body[0][value]', '', 'Comment field found.');

383
    $this->drupalGet('comment/reply/entity_test/' . $this->entity->id() . '/comment/' . $comment1->id());
384
    $this->assertResponse(403);
385
    $this->assertNoText($comment1->getSubject(), 'Comment not displayed.');
386 387 388

    // Test comment field widget changes.
    $limited_user = $this->drupalCreateUser(array(
389
      'administer entity_test fields',
390 391 392 393
      'view test entity',
      'administer entity_test content',
    ));
    $this->drupalLogin($limited_user);
394
    $this->drupalGet('entity_test/structure/entity_test/fields/entity_test.entity_test.comment');
395 396 397 398
    $this->assertNoFieldChecked('edit-default-value-input-comment-0-status-0');
    $this->assertNoFieldChecked('edit-default-value-input-comment-0-status-1');
    $this->assertFieldChecked('edit-default-value-input-comment-0-status-2');
    // Test comment option change in field settings.
399 400
    $edit = array(
      'default_value_input[comment][0][status]' => CommentItemInterface::CLOSED,
401
      'settings[anonymous]' => COMMENT_ANONYMOUS_MAY_CONTACT,
402
    );
403
    $this->drupalPostForm(NULL, $edit, t('Save settings'));
404
    $this->drupalGet('entity_test/structure/entity_test/fields/entity_test.entity_test.comment');
405 406 407
    $this->assertNoFieldChecked('edit-default-value-input-comment-0-status-0');
    $this->assertFieldChecked('edit-default-value-input-comment-0-status-1');
    $this->assertNoFieldChecked('edit-default-value-input-comment-0-status-2');
408
    $this->assertFieldByName('settings[anonymous]', COMMENT_ANONYMOUS_MAY_CONTACT);
409

410 411 412 413 414 415 416 417 418
    // Add a new comment-type.
    $bundle = CommentType::create(array(
      'id' => 'foobar',
      'label' => 'Foobar',
      'description' => '',
      'target_entity_type_id' => 'entity_test',
    ));
    $bundle->save();

419
    // Add a new comment field.
420
    $storage_edit = array(
421
      'settings[comment_type]' => 'foobar',
422 423
    );
    $this->fieldUIAddNewField('entity_test/structure/entity_test', 'foobar', 'Foobar', 'comment', $storage_edit);
424

425
    // Add a third comment field.
426
    $this->fieldUIAddNewField('entity_test/structure/entity_test', 'barfoo', 'BarFoo', 'comment', $storage_edit);
427 428

    // Check the field contains the correct comment type.
429
    $field_storage = FieldStorageConfig::load('entity_test.field_barfoo');
430 431
    $this->assertTrue($field_storage);
    $this->assertEqual($field_storage->getSetting('comment_type'), 'foobar');
432
    $this->assertEqual($field_storage->getCardinality(), 1);
433

434
    // Test the new entity commenting inherits default.
435
    $random_label = $this->randomMachineName();
436
    $data = array('bundle' => 'entity_test', 'name' => $random_label);
437
    $new_entity = EntityTest::create($data);
438
    $new_entity->save();
439
    $this->drupalGet('entity_test/manage/' . $new_entity->id() . '/edit');
440 441 442 443
    $this->assertNoFieldChecked('edit-field-foobar-0-status-1');
    $this->assertFieldChecked('edit-field-foobar-0-status-2');
    $this->assertNoField('edit-field-foobar-0-status-0');

444
    // @todo Check proper url and form https://www.drupal.org/node/2458323
445
    $this->drupalGet('comment/reply/entity_test/comment/' . $new_entity->id());
446
    $this->assertNoFieldByName('subject[0][value]', '', 'Subject field found.');
447
    $this->assertNoFieldByName('comment_body[0][value]', '', 'Comment field found.');
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465

    // Test removal of comment_body field.
    $limited_user = $this->drupalCreateUser(array(
      'administer entity_test fields',
      'post comments',
      'administer comment fields',
      'administer comment types',
    ));
    $this->drupalLogin($limited_user);

    $this->drupalGet('comment/reply/entity_test/' . $this->entity->id() . '/comment');
    $this->assertFieldByName('comment_body[0][value]', '', 'Comment body field found.');
    $this->fieldUIDeleteField('admin/structure/comment/manage/comment', 'comment.comment.comment_body', 'Comment', 'Comment settings');
    $this->drupalGet('comment/reply/entity_test/' . $this->entity->id() . '/comment');
    $this->assertNoFieldByName('comment_body[0][value]', '', 'Comment body field not found.');
    // Set subject field to autogenerate it.
    $edit = ['subject[0][value]' => ''];
    $this->drupalPostForm(NULL, $edit, t('Save'));
466 467
  }

468
  /**
469
   * Tests comment fields cannot be added to entity types without integer IDs.
470
   */
471 472
  public function testsNonIntegerIdEntities() {
    // Create a bundle for entity_test_string_id.
473 474 475 476 477
    entity_test_create_bundle('entity_test', 'Entity Test', 'entity_test_string_id');
    $limited_user = $this->drupalCreateUser(array(
      'administer entity_test_string_id fields',
    ));
    $this->drupalLogin($limited_user);
478 479
    // Visit the Field UI field add page.
    $this->drupalGet('entity_test_string_id/structure/entity_test/fields/add-field');
480
    // Ensure field isn't shown for string IDs.
481
    $this->assertNoOption('edit-new-storage-type', 'comment');
482
    // Ensure a core field type shown.
483
    $this->assertOption('edit-new-storage-type', 'boolean');
484

485
    // Create a bundle for entity_test_no_id.
486 487 488 489
    entity_test_create_bundle('entity_test', 'Entity Test', 'entity_test_no_id');
    $this->drupalLogin($this->drupalCreateUser(array(
      'administer entity_test_no_id fields',
    )));
490 491
    // Visit the Field UI field add page.
    $this->drupalGet('entity_test_no_id/structure/entity_test/fields/add-field');
492
    // Ensure field isn't shown for empty IDs.
493
    $this->assertNoOption('edit-new-storage-type', 'comment');
494
    // Ensure a core field type shown.
495
    $this->assertOption('edit-new-storage-type', 'boolean');
496 497
  }

498
}