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\field\Entity\FieldConfig;
15
use Drupal\field\Entity\FieldStorageConfig;
16
use Drupal\field_ui\Tests\FieldUiTestTrait;
17 18
use Drupal\simpletest\WebTestBase;
use Drupal\Core\Entity\EntityInterface;
19
use Drupal\user\RoleInterface;
20 21

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

28
  use FieldUiTestTrait;
29
  use CommentTestTrait;
30

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

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

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

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

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

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

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

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

    // Create a test entity.
93
    $random_label = $this->randomMachineName();
94 95
    $data = array('type' => 'entity_test', 'name' => $random_label);
    $this->entity = entity_create('entity_test', $data);
96 97 98 99 100 101 102 103
    $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.
104
   * @param string $comment
105
   *   Comment body.
106
   * @param string $subject
107
   *   Comment subject.
108
   * @param mixed $contact
109 110
   *   Set to NULL for no contact info, TRUE to ignore success checking, and
   *   array of values to set contact info.
111 112 113
   *
   * @return \Drupal\comment\CommentInterface
   *   The new comment entity.
114 115 116 117 118
   */
  function postComment(EntityInterface $entity, $comment, $subject = '', $contact = NULL) {
    $edit = array();
    $edit['comment_body[0][value]'] = $comment;

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

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

127 128 129 130
    // 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;
131 132
    }
    else {
133
      $this->assertNoFieldByName('subject[0][value]', '', 'Subject field not found.');
134 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
    }

    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])) {
172
      return Comment::load($match[1]);
173 174 175 176 177 178 179 180
    }
  }

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

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

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

  /**
   * Performs the specified operation on the specified comment.
   *
   * @param object $comment
   *   Comment to perform operation on.
   * @param string $operation
   *   Operation to perform.
219
   * @param bool $approval
220 221 222 223 224 225 226 227 228 229
   *   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'));
230
      $this->assertRaw(\Drupal::translation()->formatPlural(1, 'Deleted 1 comment.', 'Deleted @count comments.'), format_string('Operation "@operation" was performed on comment.', array('@operation' => $operation)));
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
    }
    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.
   *
   * @return integer
   *   Comment ID.
   */
  function getUnapprovedComment($subject) {
    $this->drupalGet('admin/content/comment/approval');
248
    preg_match('/href="(.*?)#comment-([^"]+)"(.*?)>(' . $subject . ')/', $this->getRawContent(), $match);
249 250 251 252 253 254 255 256 257

    return $match[2];
  }

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

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

277 278 279 280 281
    // 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.');

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

287 288 289 290 291 292 293 294 295 296 297 298 299 300
    // 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.');
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317

    // 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.
318
    $comment1 = $this->postComment($this->entity, $this->randomMachineName(), $this->randomMachineName());
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
    $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.
337
    user_role_change_permissions(RoleInterface::ANONYMOUS_ID, array(
338 339 340 341 342 343 344
      'access comments' => FALSE,
      'post comments' => FALSE,
      'skip comment approval' => FALSE,
      'view test entity' => TRUE,
    ));

    // Attempt to view comments while disallowed.
345
    $this->drupalGet('entity-test/' . $this->entity->id());
346 347 348 349
    $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.
350
    $this->drupalGet('comment/reply/entity_test/' . $this->entity->id() . '/comment');
351
    $this->assertResponse(403);
352
    $this->assertNoFieldByName('subject[0][value]', '', 'Subject field not found.');
353 354
    $this->assertNoFieldByName('comment_body[0][value]', '', 'Comment field not found.');

355
    user_role_change_permissions(RoleInterface::ANONYMOUS_ID, array(
356 357 358 359 360
      'access comments' => TRUE,
      'post comments' => FALSE,
      'view test entity' => TRUE,
      'skip comment approval' => FALSE,
    ));
361
    $this->drupalGet('entity_test/' . $this->entity->id());
362 363 364
    $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.');
365
    $this->assertNoFieldByName('subject[0][value]', '', 'Subject field not found.');
366 367 368 369 370
    $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.
371
    user_role_change_permissions(RoleInterface::ANONYMOUS_ID, array(
372 373 374 375 376
      'access comments' => FALSE,
      'post comments' => TRUE,
      'skip comment approval' => TRUE,
      'view test entity' => TRUE,
    ));
377
    $this->drupalGet('entity_test/' . $this->entity->id());
378
    $this->assertNoPattern('@<h2[^>]*>Comments</h2>@', 'Comments were not displayed.');
379
    $this->assertFieldByName('subject[0][value]', '', 'Subject field found.');
380 381
    $this->assertFieldByName('comment_body[0][value]', '', 'Comment field found.');

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

    // Test comment field widget changes.
    $limited_user = $this->drupalCreateUser(array(
388
      'administer entity_test fields',
389 390 391 392
      'view test entity',
      'administer entity_test content',
    ));
    $this->drupalLogin($limited_user);
393
    $this->drupalGet('entity_test/structure/entity_test/fields/entity_test.entity_test.comment');
394 395 396 397
    $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.
398 399
    $edit = array(
      'default_value_input[comment][0][status]' => CommentItemInterface::CLOSED,
400
      'settings[anonymous]' => COMMENT_ANONYMOUS_MAY_CONTACT,
401
    );
402
    $this->drupalPostForm(NULL, $edit, t('Save settings'));
403
    $this->drupalGet('entity_test/structure/entity_test/fields/entity_test.entity_test.comment');
404 405 406
    $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');
407
    $this->assertFieldByName('settings[anonymous]', COMMENT_ANONYMOUS_MAY_CONTACT);
408

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

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

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

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

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

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

    // 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'));
465 466
  }

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

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

497
}