public function ParagraphsContentModerationTest::testModeratedParagraphedContent

Tests the moderated paragraphed content.

File

paragraphs/modules/paragraphs_library/tests/src/FunctionalJavascript/ParagraphsContentModerationTest.php, line 125

Class

ParagraphsContentModerationTest
Tests Paragraphs, Paragraphs Library and Content Moderation integration.

Namespace

Drupal\Tests\paragraphs_library\FunctionalJavascript

Code

public function testModeratedParagraphedContent() {
  $session = $this
    ->getSession();
  $page = $session
    ->getPage();
  $assert_session = $this
    ->assertSession();

  // Create a library item.
  $this
    ->drupalGet('/admin/content/paragraphs/add/default');
  $page
    ->fillField('label[0][value]', 'Library item 1');
  $dropbutton_paragraphs = $assert_session
    ->elementExists('css', '#edit-paragraphs-add-more .dropbutton-arrow');
  $dropbutton_paragraphs
    ->click();
  $add_text_paragraph = $assert_session
    ->elementExists('css', '#paragraphs-text-add-more');
  $add_text_paragraph
    ->press();
  $textfield = $assert_session
    ->waitForElement('css', 'input[name="paragraphs[0][subform][field_text][0][value]"]');
  $this
    ->assertNotNull($textfield);
  $page
    ->fillField('paragraphs[0][subform][field_text][0][value]', 'Library item text 1');

  // Ensure it is saved as Draft by default.
  $assert_session
    ->optionExists('moderation_state[0][state]', 'draft');
  $moderation_select = $assert_session
    ->elementExists('css', 'select[name="moderation_state[0][state]"]');
  $this
    ->assertEquals('draft', $moderation_select
    ->getValue());
  $page
    ->pressButton('Save');
  $assert_session
    ->pageTextContains('Paragraph Library item 1 has been created.');

  // Double-check it was saved as draft.
  $library_item = $this
    ->getLastEntityOfType('paragraphs_library_item', TRUE);
  $this
    ->assertEquals('draft', $library_item->moderation_state->value);
  $library_item_id = $library_item
    ->id();

  // Make sure the content moderation control extra field is rendered in the
  // default view display of this library item.
  $this
    ->drupalGet("/admin/content/paragraphs/{$library_item_id}");
  $assert_session
    ->elementExists('css', '#content-moderation-entity-moderation-form');

  // Create a host node, also as a draft.
  $this
    ->drupalGet('/node/add/paragraphed_moderated_test');
  $page
    ->fillField('title[0][value]', 'Host page 1');
  $add_from_library_button = $assert_session
    ->elementExists('css', 'input[name="field_paragraphs_from_library_add_more"]');
  $add_from_library_button
    ->press();
  $button = $assert_session
    ->waitForButton('Select reusable paragraph');
  $this
    ->assertNotNull($button);
  $button
    ->press();
  $modal = $assert_session
    ->waitForElement('css', '.ui-dialog');
  $this
    ->assertNotNull($modal);
  $session
    ->switchToIFrame('entity_browser_iframe_paragraphs_library_items');
  $assert_session
    ->pageTextContains('Library item 1');

  // Select the first item from the library and accept.
  $first_row_checkbox = $assert_session
    ->elementExists('css', '.view-content tbody tr:nth-child(1) input');
  $first_row_checkbox
    ->click();
  $page
    ->pressButton('Select reusable paragraph');
  $session
    ->wait(1000);
  $session
    ->switchToIFrame();

  // Make sure the content moderation control extra field is not rendered in
  // the summary viewmode of the library item.
  $assert_session
    ->elementExists('css', '#edit-field-paragraphs-wrapper .rendered-entity');
  $assert_session
    ->elementNotExists('css', '#edit-field-paragraphs-wrapper .rendered-entity #content-moderation-entity-moderation-form');
  $page
    ->selectFieldOption('moderation_state[0][state]', 'draft');
  $page
    ->pressButton('Save');
  $assert_session
    ->pageTextContains('paragraphed_moderated_test Host page 1 has been created.');
  $host_node = $this
    ->getLastEntityOfType('node', TRUE);
  $host_node_id = $host_node
    ->id();
  $this
    ->assertFalse($host_node
    ->access('view', $this->visitorUser));

  // Create some new revisions of the host entity.
  $this
    ->drupalGet("/node/{$host_node_id}/edit");
  $page
    ->fillField('title[0][value]', 'Host page 1 (rev 2)');
  $dropbutton_paragraphs = $assert_session
    ->elementExists('css', '#edit-field-paragraphs-wrapper .dropbutton-wrapper .dropbutton-arrow');
  $dropbutton_paragraphs
    ->click();
  $add_text_paragraph = $assert_session
    ->elementExists('css', 'input[name="field_paragraphs_text_add_more"]');
  $add_text_paragraph
    ->press();
  $textfield = $assert_session
    ->waitForElement('css', 'input[name="field_paragraphs[1][subform][field_text][0][value]"]');
  $this
    ->assertNotNull($textfield);
  $page
    ->fillField('field_paragraphs[1][subform][field_text][0][value]', 'Direct paragraph text 2');
  $page
    ->selectFieldOption('moderation_state[0][state]', 'published');
  $page
    ->clickLink('Revision information');
  $page
    ->find('css', 'a[href="#edit-revision-information"]')
    ->click();
  $page
    ->fillField('revision_log[0][value]', 'Node revision #2 - This is a special version!');
  $page
    ->pressButton('Save');
  $assert_session
    ->pageTextContains('paragraphed_moderated_test Host page 1 (rev 2) has been updated.');

  // Admin users can see both paragraphs.
  $assert_session
    ->pageTextContains('Direct paragraph text 2');
  $assert_session
    ->pageTextContains('Library item text 1');

  // Normal users should see paragraph 2 (direct) but not 1 (from library).
  $this
    ->drupalLogin($this->visitorUser);
  $this
    ->drupalGet("/node/{$host_node_id}");
  $assert_session
    ->pageTextContains('Direct paragraph text 2');
  $assert_session
    ->pageTextNotContains('Library item text 1');
  $this
    ->drupalLogin($this->adminUser);

  // Create another revision by changing the direct paragraphs.
  $this
    ->drupalGet("/node/{$host_node_id}/edit");
  $page
    ->fillField('title[0][value]', 'Host page 1 (rev 3)');
  $page
    ->fillField('field_paragraphs[1][subform][field_text][0][value]', 'Direct paragraph text 2 modified');
  $dropbutton_paragraphs = $assert_session
    ->elementExists('css', '#edit-field-paragraphs-wrapper .dropbutton-wrapper .dropbutton-arrow');
  $dropbutton_paragraphs
    ->click();
  $add_text_paragraph = $assert_session
    ->elementExists('css', 'input[name="field_paragraphs_text_add_more"]');
  $add_text_paragraph
    ->press();
  $textfield = $assert_session
    ->waitForElement('css', 'input[name="field_paragraphs[2][subform][field_text][0][value]"]');
  $this
    ->assertNotNull($textfield);
  $page
    ->fillField('field_paragraphs[2][subform][field_text][0][value]', 'Direct paragraph text 3');
  $page
    ->selectFieldOption('moderation_state[0][state]', 'published');
  $page
    ->find('css', 'a[href="#edit-revision-information"]')
    ->click();
  $page
    ->fillField('revision_log[0][value]', 'Node revision #3');
  $page
    ->pressButton('Save');
  $assert_session
    ->pageTextContains('paragraphed_moderated_test Host page 1 (rev 3) has been updated.');

  // Admin users can see all paragraphs.
  $assert_session
    ->pageTextContains('Direct paragraph text 3');
  $assert_session
    ->pageTextContains('Direct paragraph text 2 modified');
  $assert_session
    ->pageTextContains('Library item text 1');

  // Normal users should see only the direct paragraphs.
  $this
    ->drupalLogin($this->visitorUser);
  $this
    ->drupalGet("/node/{$host_node_id}");
  $assert_session
    ->pageTextContains('Direct paragraph text 3');
  $assert_session
    ->pageTextContains('Direct paragraph text 2 modified');
  $assert_session
    ->pageTextNotContains('Library item text 1');
  $this
    ->drupalLogin($this->adminUser);

  // If we publish the library item, then it becomes visible immediately.
  $this
    ->drupalGet("/admin/content/paragraphs/{$library_item_id}/edit");
  $page
    ->fillField('label[0][value]', 'Library item 1 (rev 2)');
  $page
    ->selectFieldOption('moderation_state[0][state]', 'published');
  $page
    ->pressButton('Save');
  $this
    ->drupalLogin($this->visitorUser);
  $this
    ->drupalGet("/node/{$host_node_id}");
  $assert_session
    ->pageTextContains('Direct paragraph text 3');
  $assert_session
    ->pageTextContains('Direct paragraph text 2 modified');
  $assert_session
    ->pageTextContains('Library item text 1');
  $this
    ->drupalLogin($this->adminUser);

  // Do the same with some forward revisions.
  $this
    ->drupalGet("/node/{$host_node_id}/edit");
  $page
    ->fillField('title[0][value]', 'Host page 1 (rev 4)');
  $page
    ->fillField('field_paragraphs[1][subform][field_text][0][value]', 'Direct paragraph text 2 modified again');
  $row = $assert_session
    ->elementExists('css', '#field-paragraphs-add-more-wrapper tr.draggable:nth-of-type(3)');
  $dropdown = $assert_session
    ->elementExists('css', '.paragraphs-dropdown', $row);
  $dropdown
    ->click();
  $paragraph3_remove_button = $assert_session
    ->elementExists('css', 'input[name="field_paragraphs_2_remove"]');
  $paragraph3_remove_button
    ->press();
  $assert_session
    ->assertWaitOnAjaxRequest();
  $page
    ->selectFieldOption('moderation_state[0][state]', 'draft');
  $page
    ->find('css', 'a[href="#edit-revision-information"]')
    ->click();
  $page
    ->fillField('revision_log[0][value]', 'Node revision #4');
  $page
    ->pressButton('Save');

  // The admin is currently at /node/*/latest.
  $this
    ->assertNotEmpty(strpos($session
    ->getCurrentUrl(), "/node/{$host_node_id}/latest") !== FALSE);
  $assert_session
    ->pageTextContains('paragraphed_moderated_test Host page 1 (rev 4) has been updated.');

  // The admin user should be seeing the latest, forward-revision.
  $assert_session
    ->pageTextNotContains('Direct paragraph text 3');
  $assert_session
    ->pageTextContains('Direct paragraph text 2 modified again');
  $assert_session
    ->pageTextContains('Library item text 1');

  // If the admin goes to the normal node page, the default revision should be
  // shown.
  $this
    ->drupalGet("/node/{$host_node_id}");
  $assert_session
    ->pageTextContains('Direct paragraph text 3');
  $assert_session
    ->pageTextContains('Direct paragraph text 2 modified');
  $assert_session
    ->pageTextContains('Library item text 1');

  // Non-admins should also see the default revision.
  $this
    ->drupalLogin($this->visitorUser);
  $this
    ->drupalGet("/node/{$host_node_id}");
  $assert_session
    ->pageTextContains('Direct paragraph text 3');
  $assert_session
    ->pageTextContains('Direct paragraph text 2 modified');
  $assert_session
    ->pageTextContains('Library item text 1');
  $this
    ->drupalLogin($this->adminUser);

  // Release the last revision and make sure non-admins see what is expected.
  // Use the content_moderation_control widget to make this transition.
  $this
    ->drupalGet("/node/{$host_node_id}/latest");
  $page
    ->selectFieldOption('new_state', 'published');
  $content_moderation_apply_button = $assert_session
    ->elementExists('css', '#content-moderation-entity-moderation-form input[value="Apply"]');
  $content_moderation_apply_button
    ->press();
  $assert_session
    ->pageTextContains('The moderation state has been updated.');
  $this
    ->drupalLogin($this->visitorUser);
  $this
    ->drupalGet("/node/{$host_node_id}");
  $assert_session
    ->pageTextNotContains('Direct paragraph text 3');
  $assert_session
    ->pageTextContains('Direct paragraph text 2 modified again');
  $assert_session
    ->pageTextContains('Library item text 1');
  $this
    ->drupalLogin($this->adminUser);

  // Roll-back to a previous revision of the host node.
  $this
    ->drupalGet("/node/{$host_node_id}/revisions");
  $table = $assert_session
    ->elementExists('css', 'table');
  $target_row = $this
    ->getTableRowWithText($table, '- This is a special version!');
  $target_row
    ->clickLink('Revert');
  $assert_session
    ->pageTextContains('Are you sure you want to revert to the revision from');
  $page
    ->pressButton('Revert');
  $assert_session
    ->pageTextContains(' has been reverted to the revision from ');
  $this
    ->drupalLogin($this->visitorUser);
  $this
    ->drupalGet("/node/{$host_node_id}");
  $title_element = $assert_session
    ->elementExists('css', 'h1.page-title');
  $this
    ->assertEquals('Host page 1 (rev 2)', $title_element
    ->getText());
  $assert_session
    ->pageTextNotContains('Direct paragraph text 3');
  $assert_session
    ->pageTextContains('Direct paragraph text 2');
  $assert_session
    ->pageTextNotContains('Direct paragraph text 2 modified');

  // The library item is now published, so it should show up, despite the fact
  // that when this node revision was created it was not visible.
  $assert_session
    ->pageTextContains('Library item text 1');
  $this
    ->drupalLogin($this->adminUser);

  // Test some forward-revisions of the library item itself.
  $this
    ->drupalGet("/admin/content/paragraphs/{$library_item_id}/edit");
  $page
    ->fillField('label[0][value]', 'Library item 1 (rev 3)');

  // Make some modifications on this item and save it as draft.
  $page
    ->fillField('paragraphs[0][subform][field_text][0][value]', 'Library item text - Unapproved version');
  $page
    ->selectFieldOption('moderation_state[0][state]', 'draft');
  $page
    ->pressButton('Save');

  // Normal users should see the default version (non-forward).
  $this
    ->drupalLogin($this->visitorUser);
  $this
    ->drupalGet("/node/{$host_node_id}");
  $assert_session
    ->pageTextContains('Library item text 1');
  $assert_session
    ->pageTextNotContains('Library item text - Unapproved version');
  $this
    ->drupalLogin($this->adminUser);

  // Publish the forward-version and the node should reflect that immediately.
  $this
    ->drupalGet("/admin/content/paragraphs/{$library_item_id}/edit");
  $page
    ->fillField('label[0][value]', 'Library item 1 (rev 4)');
  $page
    ->fillField('paragraphs[0][subform][field_text][0][value]', 'Library item text - Approved version');
  $page
    ->selectFieldOption('moderation_state[0][state]', 'published');
  $page
    ->pressButton('Save');
  $this
    ->drupalLogin($this->visitorUser);
  $this
    ->drupalGet("/node/{$host_node_id}");
  $assert_session
    ->pageTextNotContains('Library item text 1');
  $assert_session
    ->pageTextContains('Library item text - Approved version');

  // Test some editorial workflow with the editor user as well.
  $this
    ->drupalLogin($this->editorUser);
  $this
    ->drupalGet("/admin/content/paragraphs/{$library_item_id}/edit");
  $page
    ->fillField('label[0][value]', 'Library item 1 (rev 5)');
  $page
    ->fillField('paragraphs[0][subform][field_text][0][value]', 'Library item text - Draft created by editor');
  $page
    ->selectFieldOption('moderation_state[0][state]', 'draft');
  $page
    ->pressButton('Save');
  $assert_session
    ->pageTextContains('Paragraph Library item 1 (rev 5) has been updated.');

  // The editor can see the unpublished text rendered in the library.
  $assert_session
    ->pageTextNotContains('Library item text - Approved version');
  $assert_session
    ->pageTextContains('Library item text - Draft created by editor');

  // Visitors however only see the published version.
  $this
    ->drupalLogin($this->visitorUser);
  $this
    ->drupalGet("/node/{$host_node_id}");
  $assert_session
    ->pageTextContains('Library item text - Approved version');
  $assert_session
    ->pageTextNotContains('Library item text - Draft created by editor');
  $this
    ->drupalLogin($this->editorUser);

  // The editor can edit the host node.
  $this
    ->drupalGet("/node/{$host_node_id}/edit");
  $page
    ->fillField('title[0][value]', 'Host page 1 (rev 6)');
  $page
    ->selectFieldOption('moderation_state[0][state]', 'published');
  $page
    ->find('css', 'a[href="#edit-revision-information"]')
    ->click();
  $page
    ->fillField('revision_log[0][value]', 'Node revision #6');
  $page
    ->pressButton('Save');
  $assert_session
    ->pageTextContains('paragraphed_moderated_test Host page 1 (rev 6) has been updated.');

  // The editor still sees only the published paragraph inside the node.
  $this
    ->drupalGet("/node/{$host_node_id}");
  $assert_session
    ->pageTextContains('Library item text - Approved version');
  $assert_session
    ->pageTextNotContains('Library item text - Draft created by editor');

  // @todo Investigate why this is necessary. If we don't clear caches here,
  // the form will load with the old value and save it again.
  // Remove when https://www.drupal.org/node/2951441 is solved.
  drupal_flush_all_caches();

  // If the editor publishes the paragraph item, the new text shows up.
  $this
    ->drupalGet("/admin/content/paragraphs/{$library_item_id}/edit");
  $assert_session
    ->fieldValueEquals('paragraphs[0][subform][field_text][0][value]', 'Library item text - Draft created by editor');
  $page
    ->fillField('label[0][value]', 'Library item 1 (rev 6)');
  $page
    ->selectFieldOption('moderation_state[0][state]', 'published');
  $page
    ->pressButton('Save');
  $assert_session
    ->pageTextContains('Paragraph Library item 1 (rev 6) has been updated.');

  // We should still see the same texts in the library preview.
  $assert_session
    ->pageTextNotContains('Library item text - Approved version');
  $assert_session
    ->pageTextContains('Library item text - Draft created by editor');

  // But now the node should reflect the changes as well.
  $this
    ->drupalGet("/node/{$host_node_id}");
  $assert_session
    ->pageTextNotContains('Library item text - Approved version');
  $assert_session
    ->pageTextContains('Library item text - Draft created by editor');
  $this
    ->drupalLogin($this->visitorUser);
  $this
    ->drupalGet("/node/{$host_node_id}");
  $assert_session
    ->pageTextNotContains('Library item text - Approved version');
  $assert_session
    ->pageTextContains('Library item text - Draft created by editor');

  // By this point in the test we should have created a certain number of
  // node and library item revisions. Make sure the expected counts match.
  $nodes = \Drupal::entityTypeManager()
    ->getStorage('node')
    ->getQuery()
    ->allRevisions()
    ->condition($host_node
    ->getEntityType()
    ->getKey('id'), $host_node
    ->id())
    ->accessCheck(TRUE)
    ->execute();
  $this
    ->assertEquals(7, count($nodes));
  $library_items = \Drupal::entityTypeManager()
    ->getStorage('paragraphs_library_item')
    ->getQuery()
    ->allRevisions()
    ->condition($library_item
    ->getEntityType()
    ->getKey('id'), $library_item
    ->id())
    ->accessCheck(TRUE)
    ->execute();
  $this
    ->assertEquals(6, count($library_items));

  // Assert that Paragraph types cannot be selected in the UI.
  $this
    ->drupalLogin($this->adminUser);
  $this
    ->drupalGet('admin/config/workflow/workflows/manage/' . $this->workflow
    ->id());
  $assert_session
    ->pageTextNotContains('Paragraph types');
  $assert_session
    ->pageTextContains('Content types');
  $assert_session
    ->elementNotExists('css', 'a[href$="' . $this->workflow
    ->id() . '/type/paragraph"]');
  $assert_session
    ->elementExists('css', 'a[href$="' . $this->workflow
    ->id() . '/type/node"]');

  // Promote a library and assert that is published when created.
  $paragraph_type = ParagraphsType::load('text');
  $paragraph_type
    ->setThirdPartySetting('paragraphs_library', 'allow_library_conversion', TRUE);
  $paragraph_type
    ->save();
  $this
    ->drupalGet('/node/add/paragraphed_moderated_test');
  $page
    ->fillField('title[0][value]', 'Host page 1');
  $dropbutton_paragraphs = $assert_session
    ->elementExists('css', '#field-paragraphs-add-more-wrapper .dropbutton-arrow');
  $dropbutton_paragraphs
    ->click();
  $add_text_paragraph = $assert_session
    ->elementExists('css', '#field-paragraphs-text-add-more');
  $add_text_paragraph
    ->press();
  $textfield = $assert_session
    ->waitForElement('css', 'input[name="field_paragraphs[0][subform][field_text][0][value]"]');
  $this
    ->assertNotNull($textfield);
  $page
    ->fillField('field_paragraphs[0][subform][field_text][0][value]', 'Promoted library item');
  $first_row = $assert_session
    ->elementExists('css', '#field-paragraphs-add-more-wrapper tr.draggable:nth-of-type(1)');
  $dropdown = $assert_session
    ->elementExists('css', '.paragraphs-dropdown', $first_row);
  $dropdown
    ->click();
  $add_above_button = $assert_session
    ->elementExists('css', 'input[name="field_paragraphs_0_promote_to_library"]', $first_row);
  $add_above_button
    ->click();
  $library_item = $this
    ->getLastEntityOfType('paragraphs_library_item', TRUE);
  $this
    ->assertEquals('published', $library_item->moderation_state->value);

  // Assert the unpublished indicator for library items.
  ParagraphsType::load('text')
    ->setThirdPartySetting('paragraphs_library', 'allow_library_conversion', TRUE)
    ->save();
  $this
    ->drupalGet('node/add');
  $title = $assert_session
    ->fieldExists('Title');
  $title
    ->setValue('Paragraph test');
  $element = $page
    ->find('xpath', '//*[contains(@class, "dropbutton-toggle")]');
  $element
    ->click();
  $button = $page
    ->findButton('Add text');
  $button
    ->press();
  $assert_session
    ->waitForElementVisible('css', '.ui-dialog');
  $page
    ->fillField('field_paragraphs[0][subform][field_text][0][value]', 'This is a reusable text UPDATED.');
  $first_row = $assert_session
    ->elementExists('css', '#field-paragraphs-add-more-wrapper tr.draggable:nth-of-type(1)');
  $dropdown = $assert_session
    ->elementExists('css', '.paragraphs-dropdown', $first_row);
  $dropdown
    ->click();
  $page
    ->pressButton('Promote to library');
  $assert_session
    ->assertWaitOnAjaxRequest();

  // New library items are published by default.
  $status_icon = $page
    ->find('css', '.paragraph-formatter.paragraphs-icon-view');
  $this
    ->assertNull($status_icon);

  // Archive the library item and assert there is a unpublished icon.
  $edit_button = $page
    ->find('css', 'input[name^="field_reusable_paragraph_edit_button"]');
  $edit_button
    ->press();
  $assert_session
    ->waitForElementVisible('css', '.ui-dialog');
  $assert_session
    ->elementExists('css', '.ui-dialog')
    ->selectFieldOption('moderation_state[0][state]', 'archived');
  $page
    ->find('css', '.ui-dialog-buttonset button:contains("Save")')
    ->press();
  $assert_session
    ->assertWaitOnAjaxRequest();
  $status_icon = $page
    ->find('css', '.paragraphs-icon-view');
  $this
    ->assertTrue($status_icon
    ->isVisible());
}