UiPageTest.php

Namespace

Drupal\Tests\rules\Functional

File

tests/src/Functional/UiPageTest.php

View source
<?php

namespace Drupal\Tests\rules\Functional;

use Drupal\node\Entity\NodeType;

/**
 * Tests that the Reaction Rules list builder pages work.
 *
 * @group RulesUi
 */
class UiPageTest extends RulesBrowserTestBase {
  
  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'rules',
    'rules_test',
  ];
  
  /**
   * We use the minimal profile because we want to test local action links.
   *
   * @var string
   */
  protected $profile = 'minimal';
  
  /**
   * The entity storage for Rules config entities.
   *
   * @var \Drupal\Core\Entity\EntityStorageInterface
   */
  protected $storage;
  
  /**
   * A user with administration permissions.
   *
   * @var \Drupal\user\UserInterface
   */
  protected $adminUser;
  
  /**
   * {@inheritdoc}
   */
  protected function setUp() : void {
    parent::setUp();
    $this->storage = $this->container
      ->get('entity_type.manager')
      ->getStorage('rules_reaction_rule');
    $this->adminUser = $this->drupalCreateUser([
      'administer rules',
    ]);
  }
  
  /**
   * Tests that the reaction rule listing page is reachable.
   */
  public function testReactionRulePage() {
    $account = $this->drupalCreateUser([
      'administer rules',
    ]);
    $this->drupalLogin($account);
    $this->drupalGet('admin/config/workflow/rules');
    /** @var \Drupal\Tests\WebAssert $assert */
    $assert = $this->assertSession();
    $assert->statusCodeEquals(200);
    // Test that there is an empty reaction rule listing.
    $assert->pageTextContains('There are no enabled reaction rules.');
  }
  
  /**
   * Tests that creating a reaction rule works.
   */
  public function testCreateReactionRule() {
    $this->drupalLogin($this->adminUser);
    $this->drupalGet('admin/config/workflow/rules');
    $this->clickLink('Add reaction rule');
    $this->fillField('Label', 'Test rule');
    $this->fillField('Machine-readable name', 'test_rule');
    $this->fillField('Description', 'This is a test description for a test reaction rule.');
    $this->fillField('React on event', 'rules_entity_insert:node');
    $this->pressButton('Save');
    /** @var \Drupal\Tests\WebAssert $assert */
    $assert = $this->assertSession();
    $assert->statusCodeEquals(200);
    $assert->pageTextContains('Reaction rule Test rule has been created.');
    $this->clickLink('Add condition');
    $this->fillField('Condition', 'rules_node_is_promoted');
    $this->pressButton('Continue');
    $this->fillField('context_definitions[node][setting]', 'node');
    $this->pressButton('Save');
    $assert->statusCodeEquals(200);
    $assert->pageTextContains('You have unsaved changes.');
    $this->pressButton('Save');
    $assert->pageTextContains('Reaction rule Test rule has been updated. ');
  }
  
  /**
   * Tests that enabling and disabling a rule works.
   */
  public function testRuleStatusOperations() {
    // Setup an active rule.
    $this->testCreateReactionRule();
    $this->drupalGet('admin/config/workflow/rules');
    /** @var \Drupal\Tests\WebAssert $assert */
    $assert = $this->assertSession();
    // Test disabling.
    $this->clickLink('Disable');
    $assert->pageTextContains('The reaction rule Test rule has been disabled.');
    // Test enabling.
    $this->clickLink('Enable');
    $assert->pageTextContains('The reaction rule Test rule has been enabled.');
  }
  
  /**
   * Tests that an event can be added.
   */
  public function testAddEvent() {
    // Setup an active rule.
    $this->testCreateReactionRule();
    // Go to "Add event" page.
    $this->clickLink('Add event');
    /** @var \Drupal\Tests\WebAssert $assert */
    $assert = $this->assertSession();
    $assert->pageTextContains('Add event to Test rule');
    $assert->pageTextContains('Event selection');
    $assert->pageTextContains('React on event');
    // Select an event.
    $this->findField('events[0][event_name]')
      ->selectOption('rules_entity_update:node');
    $this->pressButton('Add');
    // Click add again to ignore "Restrict by type".
    $this->pressButton('Add');
    $assert->pageTextContains('Added event After updating a content item entity to Test rule.');
    // Assert that the test rule has two events now.
    $expected = [
      'rules_entity_insert:node',
      'rules_entity_update:node',
    ];
    /** @var \Drupal\rules\Entity\ReactionRuleConfig $rule */
    $rule = $this->storage
      ->load('test_rule');
    $this->assertSame($expected, $rule->getEventNames());
  }
  
  /**
   * Tests that an event with type restriction can be added.
   */
  public function testAddEventWithRestrictByType() {
    // Add a content type called 'article'.
    $node_type = NodeType::create([
      'type' => 'article',
      'name' => 'Article',
    ]);
    $node_type->save();
    // Setup an active rule.
    $this->testCreateReactionRule();
    // Go to "Add event" page.
    $this->clickLink('Add event');
    /** @var \Drupal\Tests\WebAssert $assert */
    $assert = $this->assertSession();
    $assert->pageTextContains('Add event to Test rule');
    $assert->pageTextContains('Event selection');
    $assert->pageTextContains('React on event');
    // Select an event.
    $this->findField('events[0][event_name]')
      ->selectOption('rules_entity_update:node');
    $this->pressButton('Add');
    // Select bundle 'article'.
    $this->findField('bundle')
      ->selectOption('article');
    $this->pressButton('Add');
    $assert->pageTextContains('Added event After updating a content item entity of type Article to Test rule.');
    // Assert that the second event on the test rule has the bundle selection.
    $expected = [
      'rules_entity_insert:node',
      'rules_entity_update:node--article',
    ];
    /** @var \Drupal\rules\Entity\ReactionRuleConfig $rule */
    $rule = $this->storage
      ->load('test_rule');
    $this->assertSame($expected, $rule->getEventNames());
  }
  
  /**
   * Tests that an event can be deleted.
   */
  public function testDeleteEvent() {
    // Create a rule with two events.
    $rule = $this->storage
      ->create([
      'id' => 'test_rule',
      'label' => 'Test rule',
      'events' => [
        [
          'event_name' => 'rules_entity_insert:node',
        ],
        [
          'event_name' => 'rules_entity_update:node',
        ],
      ],
    ]);
    $rule->save();
    /** @var \Drupal\Tests\WebAssert $assert */
    $assert = $this->assertSession();
    // Login and go to the rule edit page.
    $this->drupalLogin($this->adminUser);
    $this->drupalGet('admin/config/workflow/rules/reactions/edit/test_rule');
    // Click delete button for second event.
    $this->clickLinkByHref('event-delete/rules_entity_update');
    // Assert we are on the delete page.
    $assert->pageTextContains('Are you sure you want to delete the event After updating a content item entity from Test rule?');
    // And confirm the delete.
    $this->pressButton('Delete');
    $assert->pageTextContains('Deleted event After updating a content item entity from Test rule.');
    // We need to reload the container because the container can get rebuilt
    // when saving a rule.
    $this->resetAll();
    $this->storage = $this->container
      ->get('entity_type.manager')
      ->getStorage('rules_reaction_rule');
    /** @var \Drupal\rules\Entity\ReactionRuleConfig $rule */
    $rule = $this->storage
      ->loadUnchanged('test_rule');
    // Assert that the event is really deleted.
    $this->assertSame([
      'rules_entity_insert:node',
    ], $rule->getEventNames());
  }
  
  /**
   * Tests that events cannot be deleted when there is only one event.
   */
  public function testNoDeleteEventWhenRulesHasSingleEvent() {
    // Create a rule.
    $rule = $this->storage
      ->create([
      'id' => 'test_rule',
      'label' => 'Test rule',
      'events' => [
        [
          'event_name' => 'rules_entity_insert:node',
        ],
      ],
    ]);
    $rule->save();
    // Login and go to the rule edit page.
    $this->drupalLogin($this->adminUser);
    $this->drupalGet('admin/config/workflow/rules/reactions/edit/test_rule');
    // Assert that no link is displayed for deleting the only event that there
    // is.
    $this->assertNull($this->getSession()
      ->getPage()
      ->find('xpath', './/a[contains(@href, "event-delete/rules_entity_insert")]'));
    // Try to delete the event anyway and assert that access to that page is
    // denied.
    $this->drupalGet('admin/config/workflow/rules/reactions/edit/test_rule/event-delete/rules_entity_insert:node');
    /** @var \Drupal\Tests\WebAssert $assert */
    $assert = $this->assertSession();
    $assert->statusCodeEquals(403);
  }
  
  /**
   * Tests that cancelling an expression from a rule works.
   */
  public function testCancelExpressionInRule() {
    // Setup a rule with one condition.
    $this->testCreateReactionRule();
    $this->clickLink('Add condition');
    $this->fillField('Condition', 'rules_node_is_promoted');
    $this->pressButton('Continue');
    $this->fillField('context_definitions[node][setting]', 'node');
    $this->pressButton('Save');
    /** @var \Drupal\Tests\WebAssert $assert */
    $assert = $this->assertSession();
    $assert->pageTextContains('You have unsaved changes.');
    // Edit and cancel.
    $this->pressButton('Cancel');
    $assert->pageTextContains('Canceled.');
    // Make sure that we are back at the overview listing page.
    $this->assertEquals(1, preg_match('#/admin/config/workflow/rules$#', $this->getSession()
      ->getCurrentUrl()));
  }
  
  /**
   * Tests that deleting an expression from a rule works.
   */
  public function testDeleteExpressionInRule() {
    // Setup a rule with one condition.
    $this->testCreateReactionRule();
    /** @var \Drupal\Tests\WebAssert $assert */
    $assert = $this->assertSession();
    $this->clickLink('Delete');
    $assert->pageTextContains('Are you sure you want to delete Node is promoted from Test rule?');
    $this->pressButton('Delete');
    $assert->pageTextContains('You have unsaved changes.');
    $this->pressButton('Save');
    $assert->pageTextContains('Reaction rule Test rule has been updated. ');
  }
  
  /**
   * Tests that a condition with no context can be configured.
   */
  public function testNoContextCondition() {
    // Setup a rule with one condition.
    $this->testCreateReactionRule();
    $this->clickLink('Add condition');
    // The rules_test_true condition does not define context in its annotation.
    $this->fillField('Condition', 'rules_test_true');
    $this->pressButton('Continue');
    // Pressing 'Save' will generate an exception and the test will fail if
    // Rules does not support conditions without a context.
    // Exception: Warning: Invalid argument supplied for foreach().
    $this->pressButton('Save');
  }
  
  /**
   * Tests that a negated condition has NOT prefixed to its label.
   */
  public function testNegatedCondition() {
    // Setup a rule with one condition.
    $this->testCreateReactionRule();
    /** @var \Drupal\Tests\WebAssert $assert */
    $assert = $this->assertSession();
    // Check that the label shows up on the Rule edit page.
    $assert->pageTextContains('Node is promoted');
    // Edit the condition, negate it, then check the label again.
    $this->clickLink('Edit');
    $this->fillField('Negate', 1);
    $this->pressButton('Save');
    $assert->pageTextContains('NOT Node is promoted');
  }
  
  /**
   * Tests that an action with a 'multiple' context can be configured.
   */
  public function testMultipleContextAction() {
    $this->drupalLogin($this->adminUser);
    $this->drupalGet('admin/config/workflow/rules');
    $this->clickLink('Add reaction rule');
    $this->fillField('Label', 'Test rule');
    $this->fillField('Machine-readable name', 'test_rule');
    $this->fillField('React on event', 'rules_entity_insert:node');
    $this->pressButton('Save');
    $this->clickLink('Add action');
    $this->fillField('Action', 'rules_send_email');
    $this->pressButton('Continue');
    // Push the data selection switch 2 times to make sure that also works and
    // does not throw PHP notices.
    $this->pressButton('Switch to data selection');
    $this->pressButton('Switch to the direct input mode');
    $this->fillField('context_definitions[to][setting]', 'klausi@example.com');
    $this->fillField('context_definitions[subject][setting]', 'subject');
    $this->fillField('context_definitions[message][setting]', 'message');
    $this->pressButton('Save');
    /** @var \Drupal\Tests\WebAssert $assert */
    $assert = $this->assertSession();
    $assert->statusCodeEquals(200);
  }

}

Classes

Title Deprecated Summary
UiPageTest Tests that the Reaction Rules list builder pages work.