X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=web%2Fcore%2Fmodules%2Fcontent_moderation%2Ftests%2Fsrc%2FFunctional%2FModerationFormTest.php;fp=web%2Fcore%2Fmodules%2Fcontent_moderation%2Ftests%2Fsrc%2FFunctional%2FModerationFormTest.php;h=13fd0c0571a7efdd9463d0219cb6b44ec88bb397;hp=3882c764f191193c197e0213246cc9bbf45e6e9e;hb=9917807b03b64faf00f6a1f29dcb6eafc454efa5;hpb=aea91e65e895364e460983b890e295aa5d5540a5 diff --git a/web/core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php b/web/core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php index 3882c764f..13fd0c057 100644 --- a/web/core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php +++ b/web/core/modules/content_moderation/tests/src/Functional/ModerationFormTest.php @@ -11,6 +11,18 @@ use Drupal\workflows\Entity\Workflow; */ class ModerationFormTest extends ModerationStateTestBase { + /** + * Modules to enable. + * + * @var array + */ + public static $modules = [ + 'node', + 'content_moderation', + 'locale', + 'content_translation', + ]; + /** * {@inheritdoc} */ @@ -24,9 +36,7 @@ class ModerationFormTest extends ModerationStateTestBase { /** * Tests the moderation form that shows on the latest version page. * - * The latest version page only shows if there is a forward revision. There - * is only a forward revision if a draft revision is created on a node where - * the default revision is not a published moderation state. + * The latest version page only shows if there is a pending revision. * * @see \Drupal\content_moderation\EntityOperations * @see \Drupal\Tests\content_moderation\Functional\ModerationStateBlockTest::testCustomBlockModeration @@ -36,7 +46,8 @@ class ModerationFormTest extends ModerationStateTestBase { $this->drupalPostForm('node/add/moderated_content', [ 'title[0][value]' => 'Some moderated content', 'body[0][value]' => 'First version of the content.', - ], t('Save and Create New Draft')); + 'moderation_state[0][state]' => 'draft', + ], t('Save')); $node = $this->drupalGetNodeByTitle('Some moderated content'); $canonical_path = sprintf('node/%d', $node->id()); @@ -51,7 +62,7 @@ class ModerationFormTest extends ModerationStateTestBase { $this->assertResponse(200); $this->assertField('edit-new-state', 'The node view page has a moderation form.'); - // The latest version page should not show, because there is no forward + // The latest version page should not show, because there is no pending // revision. $this->drupalGet($latest_version_path); $this->assertResponse(403); @@ -59,7 +70,8 @@ class ModerationFormTest extends ModerationStateTestBase { // Update the draft. $this->drupalPostForm($edit_path, [ 'body[0][value]' => 'Second version of the content.', - ], t('Save and Create New Draft')); + 'moderation_state[0][state]' => 'draft', + ], t('Save')); // The canonical view should have a moderation form, because it is not the // live revision. @@ -68,14 +80,15 @@ class ModerationFormTest extends ModerationStateTestBase { $this->assertField('edit-new-state', 'The node view page has a moderation form.'); // The latest version page should not show, because there is still no - // forward revision. + // pending revision. $this->drupalGet($latest_version_path); $this->assertResponse(403); // Publish the draft. $this->drupalPostForm($edit_path, [ 'body[0][value]' => 'Third version of the content.', - ], t('Save and Publish')); + 'moderation_state[0][state]' => 'published', + ], t('Save')); // The published view should not have a moderation form, because it is the // live revision. @@ -84,14 +97,15 @@ class ModerationFormTest extends ModerationStateTestBase { $this->assertNoField('edit-new-state', 'The node view page has no moderation form.'); // The latest version page should not show, because there is still no - // forward revision. + // pending revision. $this->drupalGet($latest_version_path); $this->assertResponse(403); - // Make a forward revision. + // Make a pending revision. $this->drupalPostForm($edit_path, [ 'body[0][value]' => 'Fourth version of the content.', - ], t('Save and Create New Draft')); + 'moderation_state[0][state]' => 'draft', + ], t('Save')); // The published view should not have a moderation form, because it is the // live revision. @@ -100,7 +114,7 @@ class ModerationFormTest extends ModerationStateTestBase { $this->assertNoField('edit-new-state', 'The node view page has no moderation form.'); // The latest version page should show the moderation form and have "Draft" - // status, because the forward revision is in "Draft". + // status, because the pending revision is in "Draft". $this->drupalGet($latest_version_path); $this->assertResponse(200); $this->assertField('edit-new-state', 'The latest-version page has a moderation form.'); @@ -112,7 +126,7 @@ class ModerationFormTest extends ModerationStateTestBase { ], t('Apply')); // The latest version page should not show, because there is no - // forward revision. + // pending revision. $this->drupalGet($latest_version_path); $this->assertResponse(403); } @@ -127,23 +141,23 @@ class ModerationFormTest extends ModerationStateTestBase { $workflow->save(); // Create new moderated content in draft. - $this->drupalPostForm('entity_test_mulrevpub/add', [], t('Save and Create New Draft')); + $this->drupalPostForm('entity_test_mulrevpub/add', ['moderation_state[0][state]' => 'draft'], t('Save')); - // The latest version page should not show, because there is no forward + // The latest version page should not show, because there is no pending // revision. $this->drupalGet('/entity_test_mulrevpub/manage/1/latest'); $this->assertResponse(403); // Update the draft. - $this->drupalPostForm('entity_test_mulrevpub/manage/1/edit', [], t('Save and Create New Draft')); + $this->drupalPostForm('entity_test_mulrevpub/manage/1/edit', ['moderation_state[0][state]' => 'draft'], t('Save')); // The latest version page should not show, because there is still no - // forward revision. + // pending revision. $this->drupalGet('/entity_test_mulrevpub/manage/1/latest'); $this->assertResponse(403); // Publish the draft. - $this->drupalPostForm('entity_test_mulrevpub/manage/1/edit', [], t('Save and Publish')); + $this->drupalPostForm('entity_test_mulrevpub/manage/1/edit', ['moderation_state[0][state]' => 'published'], t('Save')); // The published view should not have a moderation form, because it is the // default revision. @@ -152,12 +166,12 @@ class ModerationFormTest extends ModerationStateTestBase { $this->assertNoText('Status', 'The node view page has no moderation form.'); // The latest version page should not show, because there is still no - // forward revision. + // pending revision. $this->drupalGet('entity_test_mulrevpub/manage/1/latest'); $this->assertResponse(403); - // Make a forward revision. - $this->drupalPostForm('entity_test_mulrevpub/manage/1/edit', [], t('Save and Create New Draft')); + // Make a pending revision. + $this->drupalPostForm('entity_test_mulrevpub/manage/1/edit', ['moderation_state[0][state]' => 'draft'], t('Save')); // The published view should not have a moderation form, because it is the // default revision. @@ -166,10 +180,10 @@ class ModerationFormTest extends ModerationStateTestBase { $this->assertNoText('Status', 'The node view page has no moderation form.'); // The latest version page should show the moderation form and have "Draft" - // status, because the forward revision is in "Draft". + // status, because the pending revision is in "Draft". $this->drupalGet('entity_test_mulrevpub/manage/1/latest'); $this->assertResponse(200); - $this->assertText('Status', 'Form text found on the latest-version page.'); + $this->assertText('Moderation state', 'Form text found on the latest-version page.'); $this->assertText('Draft', 'Correct status found on the latest-version page.'); // Submit the moderation form to change status to published. @@ -178,7 +192,7 @@ class ModerationFormTest extends ModerationStateTestBase { ], t('Apply')); // The latest version page should not show, because there is no - // forward revision. + // pending revision. $this->drupalGet('entity_test_mulrevpub/manage/1/latest'); $this->assertResponse(403); } @@ -189,9 +203,10 @@ class ModerationFormTest extends ModerationStateTestBase { public function testModerationFormSetsRevisionAuthor() { // Create new moderated content in published. $node = $this->createNode(['type' => 'moderated_content', 'moderation_state' => 'published']); - // Make a forward revision. + // Make a pending revision. $node->title = $this->randomMachineName(); $node->moderation_state->value = 'draft'; + $node->setRevisionCreationTime(12345); $node->save(); $another_user = $this->drupalCreateUser($this->permissions); @@ -203,6 +218,316 @@ class ModerationFormTest extends ModerationStateTestBase { $this->drupalGet(sprintf('node/%d/revisions', $node->id())); $this->assertText('by ' . $another_user->getAccountName()); + + // Verify the revision creation time has been updated. + $node = $node->load($node->id()); + $this->assertGreaterThan(12345, $node->getRevisionCreationTime()); + } + + /** + * Tests translated and moderated nodes. + */ + public function testContentTranslationNodeForm() { + $this->drupalLogin($this->rootUser); + + // Add French language. + $edit = [ + 'predefined_langcode' => 'fr', + ]; + $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language')); + + // Enable content translation on articles. + $this->drupalGet('admin/config/regional/content-language'); + $edit = [ + 'entity_types[node]' => TRUE, + 'settings[node][moderated_content][translatable]' => TRUE, + 'settings[node][moderated_content][settings][language][language_alterable]' => TRUE, + ]; + $this->drupalPostForm(NULL, $edit, t('Save configuration')); + + // Adding languages requires a container rebuild in the test running + // environment so that multilingual services are used. + $this->rebuildContainer(); + + // Create new moderated content in draft (revision 1). + $this->drupalPostForm('node/add/moderated_content', [ + 'title[0][value]' => 'Some moderated content', + 'body[0][value]' => 'First version of the content.', + 'moderation_state[0][state]' => 'draft', + ], t('Save')); + $this->assertTrue($this->xpath('//ul[@class="entity-moderation-form"]')); + + $node = $this->drupalGetNodeByTitle('Some moderated content'); + $this->assertTrue($node->language(), 'en'); + $edit_path = sprintf('node/%d/edit', $node->id()); + $translate_path = sprintf('node/%d/translations/add/en/fr', $node->id()); + $latest_version_path = sprintf('node/%d/latest', $node->id()); + $french = \Drupal::languageManager()->getLanguage('fr'); + + $this->drupalGet($latest_version_path); + $this->assertSession()->statusCodeEquals('403'); + $this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]')); + + // Add french translation (revision 2). + $this->drupalGet($translate_path); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'body[0][value]' => 'Second version of the content.', + 'moderation_state[0][state]' => 'published', + ], t('Save (this translation)')); + + $this->drupalGet($latest_version_path, ['language' => $french]); + $this->assertSession()->statusCodeEquals('403'); + $this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]')); + + // Add french pending revision (revision 3). + $this->drupalGet($edit_path, ['language' => $french]); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'body[0][value]' => 'Third version of the content.', + 'moderation_state[0][state]' => 'draft', + ], t('Save (this translation)')); + + $this->drupalGet($latest_version_path, ['language' => $french]); + $this->assertTrue($this->xpath('//ul[@class="entity-moderation-form"]')); + + // It should not be possible to add a new english revision. + $this->drupalGet($edit_path); + $this->assertSession()->fieldNotExists('moderation_state[0][state]'); + $this->assertSession()->pageTextContains('Unable to save this Moderated content.'); + + $this->clickLink('Publish'); + $this->assertSession()->fieldValueEquals('body[0][value]', 'Third version of the content.'); + + $this->drupalGet($edit_path); + $this->clickLink('Delete'); + $this->assertSession()->buttonExists('Delete'); + + $this->drupalGet($latest_version_path); + $this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]')); + + // Publish the french pending revision (revision 4). + $this->drupalGet($edit_path, ['language' => $french]); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'body[0][value]' => 'Fifth version of the content.', + 'moderation_state[0][state]' => 'published', + ], t('Save (this translation)')); + + $this->drupalGet($latest_version_path, ['language' => $french]); + $this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]')); + + // Now we can publish the english (revision 5). + $this->drupalGet($edit_path); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'body[0][value]' => 'Sixth version of the content.', + 'moderation_state[0][state]' => 'published', + ], t('Save (this translation)')); + + $this->drupalGet($latest_version_path); + $this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]')); + + // Make sure we're allowed to create a pending french revision. + $this->drupalGet($edit_path, ['language' => $french]); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); + + // Add a english pending revision (revision 6). + $this->drupalGet($edit_path); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'body[0][value]' => 'Seventh version of the content.', + 'moderation_state[0][state]' => 'draft', + ], t('Save (this translation)')); + + $this->drupalGet($latest_version_path); + $this->assertTrue($this->xpath('//ul[@class="entity-moderation-form"]')); + + // Make sure we're not allowed to create a pending french revision. + $this->drupalGet($edit_path, ['language' => $french]); + $this->assertSession()->fieldNotExists('moderation_state[0][state]'); + $this->assertSession()->pageTextContains('Unable to save this Moderated content.'); + + $this->drupalGet($latest_version_path, ['language' => $french]); + $this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]')); + + // We should be able to publish the english pending revision (revision 7) + $this->drupalGet($edit_path); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'body[0][value]' => 'Eighth version of the content.', + 'moderation_state[0][state]' => 'published', + ], t('Save (this translation)')); + + $this->drupalGet($latest_version_path); + $this->assertFalse($this->xpath('//ul[@class="entity-moderation-form"]')); + + // Make sure we're allowed to create a pending french revision. + $this->drupalGet($edit_path, ['language' => $french]); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); + + // Make sure we're allowed to create a pending english revision. + $this->drupalGet($edit_path); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); + + // Create new moderated content. (revision 1). + $this->drupalPostForm('node/add/moderated_content', [ + 'title[0][value]' => 'Second moderated content', + 'body[0][value]' => 'First version of the content.', + 'moderation_state[0][state]' => 'published', + ], t('Save')); + + $node = $this->drupalGetNodeByTitle('Second moderated content'); + $this->assertTrue($node->language(), 'en'); + $edit_path = sprintf('node/%d/edit', $node->id()); + $translate_path = sprintf('node/%d/translations/add/en/fr', $node->id()); + + // Add a pending revision (revision 2). + $this->drupalGet($edit_path); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'body[0][value]' => 'Second version of the content.', + 'moderation_state[0][state]' => 'draft', + ], t('Save')); + + // It shouldn't be possible to translate as we have a pending revision. + $this->drupalGet($translate_path); + $this->assertSession()->fieldNotExists('moderation_state[0][state]'); + $this->assertSession()->pageTextContains('Unable to save this Moderated content.'); + + // Create new moderated content (revision 1). + $this->drupalPostForm('node/add/moderated_content', [ + 'title[0][value]' => 'Third moderated content', + 'moderation_state[0][state]' => 'published', + ], t('Save')); + + $node = $this->drupalGetNodeByTitle('Third moderated content'); + $this->assertTrue($node->language(), 'en'); + $edit_path = sprintf('node/%d/edit', $node->id()); + $translate_path = sprintf('node/%d/translations/add/en/fr', $node->id()); + + // Translate it, without updating data (revision 2). + $this->drupalGet($translate_path); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'moderation_state[0][state]' => 'draft', + ], t('Save (this translation)')); + + // Add another draft for the translation (revision 3). + $this->drupalGet($edit_path, ['language' => $french]); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'moderation_state[0][state]' => 'draft', + ], t('Save (this translation)')); + + // Editing the original translation should not be possible. + $this->drupalGet($edit_path); + $this->assertSession()->fieldNotExists('moderation_state[0][state]'); + $this->assertSession()->pageTextContains('Unable to save this Moderated content.'); + + // Updating and publishing the french translation is still possible. + $this->drupalGet($edit_path, ['language' => $french]); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionNotExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'moderation_state[0][state]' => 'published', + ], t('Save (this translation)')); + + // Now the french translation is published, an english draft can be added. + $this->drupalGet($edit_path); + $this->assertSession()->optionExists('moderation_state[0][state]', 'draft'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'published'); + $this->assertSession()->optionExists('moderation_state[0][state]', 'archived'); + $this->drupalPostForm(NULL, [ + 'moderation_state[0][state]' => 'draft', + ], t('Save (this translation)')); + } + + /** + * Tests that workflows and states can not be deleted if they are in use. + * + * @covers \Drupal\content_moderation\Plugin\WorkflowType\ContentModeration::workflowHasData + * @covers \Drupal\content_moderation\Plugin\WorkflowType\ContentModeration::workflowStateHasData + */ + public function testWorkflowInUse() { + $user = $this->createUser([ + 'administer workflows', + 'create moderated_content content', + 'edit own moderated_content content', + 'use editorial transition create_new_draft', + 'use editorial transition publish', + 'use editorial transition archive' + ]); + $this->drupalLogin($user); + $paths = [ + 'archived_state' => 'admin/config/workflow/workflows/manage/editorial/state/archived/delete', + 'editorial_workflow' => 'admin/config/workflow/workflows/manage/editorial/delete', + ]; + $messages = [ + 'archived_state' => 'This workflow state is in use. You cannot remove this workflow state until you have removed all content using it.', + 'editorial_workflow' => 'This workflow is in use. You cannot remove this workflow until you have removed all content using it.', + ]; + foreach ($paths as $path) { + $this->drupalGet($path); + $this->assertSession()->buttonExists('Delete'); + } + // Create new moderated content in draft. + $this->drupalPostForm('node/add/moderated_content', [ + 'title[0][value]' => 'Some moderated content', + 'body[0][value]' => 'First version of the content.', + 'moderation_state[0][state]' => 'draft', + ], 'Save'); + + // The archived state is not used yet, so can still be deleted. + $this->drupalGet($paths['archived_state']); + $this->assertSession()->buttonExists('Delete'); + + // The workflow is being used, so can't be deleted. + $this->drupalGet($paths['editorial_workflow']); + $this->assertSession()->buttonNotExists('Delete'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->pageTextContains($messages['editorial_workflow']); + + $node = $this->drupalGetNodeByTitle('Some moderated content'); + $this->drupalPostForm('node/' . $node->id() . '/edit', [ + 'moderation_state[0][state]' => 'published', + ], 'Save'); + $this->drupalPostForm('node/' . $node->id() . '/edit', [ + 'moderation_state[0][state]' => 'archived', + ], 'Save'); + + // Now the archived state is being used so it can not be deleted either. + foreach ($paths as $type => $path) { + $this->drupalGet($path); + $this->assertSession()->buttonNotExists('Delete'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->pageTextContains($messages[$type]); + } } }