/**
  * Simulates the scheduled (un)publication of a node.
  *
  * @param \Drupal\node\NodeInterface $node
  *   The node to schedule.
  * @param string $action
  *   The action to perform: either 'publish' or 'unpublish'. Defaults to
  *   'publish'.
  *
  * @return \Drupal\node\NodeInterface
  *   The updated node, after scheduled (un)publication via a cron run.
  */
 protected function schedule(NodeInterface $node, $action = 'publish')
 {
     $node_storage = $this->container->get('entity.manager')->getStorage('node');
     // Simulate scheduling by setting the (un)publication date in the past and
     // running cron.
     $node->{$action . '_on'} = strtotime('-1 day');
     $node->save();
     scheduler_cron();
     $node_storage->resetCache(array($node->id()));
     return $node_storage->load($node->id());
 }
 /**
  * Test the different options for past publication dates.
  */
 public function testSchedulerPastDates()
 {
     /** @var EntityStorageInterface $node_storage */
     $node_storage = $this->container->get('entity_type.manager')->getStorage('node');
     // Log in.
     $this->drupalLogin($this->adminUser);
     // Ensure that neither of the scheduling dates are set to be required.
     $this->nodetype->setThirdPartySetting('scheduler', 'publish_required', FALSE)->setThirdPartySetting('scheduler', 'unpublish_required', FALSE)->save();
     // Create an unpublished page node.
     $node = $this->drupalCreateNode(['type' => $this->nodetype->get('type'), 'status' => FALSE]);
     // Test the default behavior: an error message should be shown when the user
     // enters a publication date that is in the past.
     $edit = ['title[0][value]' => t('Past') . ' ' . $this->randomString(10), 'publish_on[0][value][date]' => \Drupal::service('date.formatter')->format(strtotime('-1 day'), 'custom', 'Y-m-d'), 'publish_on[0][value][time]' => \Drupal::service('date.formatter')->format(strtotime('-1 day'), 'custom', 'H:i:s')];
     $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and publish'));
     $this->assertRaw(t("The 'publish on' date must be in the future"), 'An error message is shown by default when the publication date is in the past.');
     // Test the 'error' behavior explicitly.
     $this->nodetype->setThirdPartySetting('scheduler', 'publish_past_date', 'error')->save();
     $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and publish'));
     $this->assertRaw(t("The 'publish on' date must be in the future"), 'An error message is shown when the publication date is in the past and the "error" behavior is chosen.');
     // Test the 'publish' behavior: the node should be published immediately.
     $this->nodetype->setThirdPartySetting('scheduler', 'publish_past_date', 'publish')->save();
     $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and publish'));
     $this->assertNoRaw(t("The 'publish on' date must be in the future"), 'No error message is shown when the publication date is in the past and the "publish" behavior is chosen.');
     $this->assertRaw(t('@type %title has been updated.', ['@type' => t('Basic page'), '%title' => SafeMarkup::checkPlain($edit['title[0][value]'])]), 'The node is saved successfully when the publication date is in the past and the "publish" behavior is chosen.');
     // Reload the changed node and check that it is published.
     $node_storage->resetCache([$node->id()]);
     /** @var NodeInterface $node */
     $node = $node_storage->load($node->id());
     $this->assertTrue($node->isPublished(), 'The node has been published immediately when the publication date is in the past and the "publish" behavior is chosen.');
     $this->assertNull($node->publish_on->value, 'The node publish_on date has been removed after publishing when the "publish" behavior is chosen.');
     // Test the 'schedule' behavior: the node should be unpublished and become
     // published on the next cron run.
     $this->nodetype->setThirdPartySetting('scheduler', 'publish_past_date', 'schedule')->save();
     $this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published'));
     $publish_time = $edit['publish_on[0][value][date]'] . ' ' . $edit['publish_on[0][value][time]'];
     ### @TODO should use date format from config
     $this->assertNoRaw(t("The 'publish on' date must be in the future"), 'No error message is shown when the publication date is in the past and the "schedule" behavior is chosen.');
     $this->assertRaw(t('@type %title has been updated.', ['@type' => t('Basic page'), '%title' => SafeMarkup::checkPlain($edit['title[0][value]'])]), 'The node is saved successfully when the publication date is in the past and the "schedule" behavior is chosen.');
     $this->assertRaw(t('This post is unpublished and will be published @publish_time.', ['@publish_time' => $publish_time]), 'The node is scheduled to be published when the publication date is in the past and the "schedule" behavior is chosen.');
     // Reload the node and check that it is unpublished but scheduled correctly.
     $node_storage->resetCache([$node->id()]);
     $node = $node_storage->load($node->id());
     $this->assertFalse($node->isPublished(), 'The node has been unpublished when the publication date is in the past and the "schedule" behavior is chosen.');
     $this->assertEqual(\Drupal::service('date.formatter')->format($node->publish_on->value, 'custom', 'Y-m-d H:i:s'), $publish_time, 'The node is scheduled for the required date');
     // Simulate a cron run and check that the node is published.
     scheduler_cron();
     $node_storage->resetCache([$node->id()]);
     $node = $node_storage->load($node->id());
     $this->assertTrue($node->isPublished(), 'The node with publication date in the past and the "schedule" behavior has now been published by cron.');
     // Check that an Unpublish date in the past fails validation.
     $edit = ['title[0][value]' => t('Unpublish in the past') . ' ' . $this->randomString(10), 'unpublish_on[0][value][date]' => \Drupal::service('date.formatter')->format(REQUEST_TIME - 3600, 'custom', 'Y-m-d'), 'unpublish_on[0][value][time]' => \Drupal::service('date.formatter')->format(REQUEST_TIME - 3600, 'custom', 'H:i:s')];
     $this->drupalPostForm('node/add/page', $edit, t('Save and publish'));
     $this->assertRaw(t("The 'unpublish on' date must be in the future"), 'An error message is shown when the unpublish date is in the past.');
 }
 /**
  * Tests hook_scheduler_allow().
  *
  * This hook can allow or deny the (un)publication of individual nodes. This
  * test uses a content type which has checkboxes 'Approved for publication'
  * and 'Approved for unpublication'. The node may only be published or 
  * unpublished if the appropriate checkbox is ticked.
  *
  * @todo Create and update the nodes through the interface so we can check if
  *   the correct messages are displayed.
  */
 public function testAllowedPublishingAndUnpublishing()
 {
     if (empty($this->nodetype)) {
         $this->fail('*** Custom node type ' . $this->custom_type . ' does not exist. Testing abandoned ***');
         return;
     }
     // Check that the approved fields are shown on the node/add form.
     $this->drupalLogin($this->webUser);
     $this->drupalGet('node/add/' . $this->custom_type);
     $this->assertFieldById('edit-field-approved-publishing-value', '', 'The "Approved for publishing" field is shown on the node form');
     $this->assertFieldById('edit-field-approved-unpublishing-value', '', 'The "Approved for unpublishing" field is shown on the node form');
     // Create a node that is scheduled but not approved for publication. Then
     // simulate a cron run, and check that the node is still not published.
     $node = $this->createUnapprovedNode('publish_on');
     scheduler_cron();
     $this->node_storage->resetCache(array($node->id()));
     $node = $this->node_storage->load($node->id());
     $this->assertFalse($node->isPublished(), 'An unapproved node is not published during cron processing.');
     // Approve the node for publication, simulate a cron run and check that the
     // node is now published.
     $this->approveNode($node->id(), 'field_approved_publishing');
     scheduler_cron();
     $this->node_storage->resetCache(array($node->id()));
     $node = $this->node_storage->load($node->id());
     $this->assertTrue($node->isPublished(), 'An approved node is published during cron processing.');
     // Turn on immediate publication of nodes with publication dates in the past
     // and repeat the tests. It is not needed to simulate cron runs here.
     $this->nodetype->setThirdPartySetting('scheduler', 'publish_past_date', 'publish')->save();
     $node = $this->createUnapprovedNode('publish_on');
     $this->assertFalse($node->isPublished(), 'An unapproved node with a date in the past is not published immediately after saving.');
     // Check that the node can be approved and published programatically.
     $this->approveNode($node->id(), 'field_approved_publishing');
     $this->node_storage->resetCache(array($node->id()));
     $node = $this->node_storage->load($node->id());
     $this->assertTrue($node->isPublished(), 'An approved node with a date in the past is published immediately via $node->set()->save().');
     // Check that a node can be approved and published via edit form.
     $node = $this->createUnapprovedNode('publish_on');
     $this->drupalPostForm('node/' . $node->id() . '/edit', ['field_approved_publishing[value]' => '1'], t('Save'));
     $this->node_storage->resetCache(array($node->id()));
     $node = $this->node_storage->load($node->id());
     $this->assertTrue($node->isPublished(), 'An approved node with a date in the past is published immediately after saving via edit form.');
     // Test approval for unpublishing. This is simpler than the test sequence
     // for publishing, because the 'immediate' option is not applicable.
     // Create a node that is scheduled but not approved for unpublication. Then
     // simulate a cron run, and check that the node is still published.
     $node = $this->createUnapprovedNode('unpublish_on');
     scheduler_cron();
     $this->node_storage->resetCache(array($node->id()));
     $node = $this->node_storage->load($node->id());
     $this->assertTrue($node->isPublished(), 'An unapproved node is not unpublished during cron processing.');
     // Approve the node for unpublishing, simulate a cron run and check that
     // the node is now unpublished.
     $this->approveNode($node->id(), 'field_approved_unpublishing');
     scheduler_cron();
     $this->node_storage->resetCache(array($node->id()));
     $node = $this->node_storage->load($node->id());
     $this->assertFalse($node->isPublished(), 'An approved node is unpublished during cron processing.');
 }