You are here

class EntityContext in Lightning Core 8.2

Same name and namespace in other branches
  1. 8.5 tests/contexts/EntityContext.behat.inc \Acquia\LightningExtension\Context\EntityContext
  2. 8 tests/contexts/EntityContext.behat.inc \Acquia\LightningExtension\Context\EntityContext
  3. 8.3 tests/contexts/EntityContext.behat.inc \Acquia\LightningExtension\Context\EntityContext
  4. 8.4 tests/contexts/EntityContext.behat.inc \Acquia\LightningExtension\Context\EntityContext

Contains miscellaneous step definitions for working with Drupal entities.

@internal This class is part of Lightning's internal testing code. It is not an API and should not be extended. This class will be marked final, and all protected members will be made private, in Lightning Core 3.x.

Hierarchy

  • class \Acquia\LightningExtension\Context\EntityContext extends \Drupal\DrupalExtension\Context\DrupalSubContextBase

Expanded class hierarchy of EntityContext

File

tests/contexts/EntityContext.behat.inc, line 21

Namespace

Acquia\LightningExtension\Context
View source
class EntityContext extends DrupalSubContextBase {

  /**
   * IDs of entities created during the scenario, divided into sets keyed by
   * entity type ID.
   *
   * @var array
   */
  protected $trash = [];

  /**
   * Saves an entity, ensuring automatic clean-up.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity to save.
   */
  public function save(EntityInterface $entity) {
    $uid = $this
      ->getUser();
    if ($uid && $entity instanceof EntityOwnerInterface && $entity
      ->getOwnerId() == 0) {
      $entity
        ->setOwnerId($uid)
        ->save();
    }
    else {
      $entity
        ->save();
      $entity_type = $entity
        ->getEntityTypeId();
      $this->trash[$entity_type][] = $entity
        ->id();
    }
  }

  /**
   * Creates a set of entities from tabular data.
   *
   * @param string $entity_type
   *   The entity type ID.
   * @param \Behat\Gherkin\Node\TableNode $table
   *   The table of entity data.
   *
   * @Given :entity_type entities:
   */
  public function createMultiple($entity_type, TableNode $table) {
    $storage = \Drupal::entityTypeManager()
      ->getStorage($entity_type);
    foreach ($table as $values) {
      $this
        ->save($storage
        ->create($values));
    }
  }

  /**
   * Deletes entities created during the scenario.
   *
   * @afterScenario
   */
  public function tearDown() {
    foreach ($this->trash as $entity_type => $IDs) {

      /** @var \Drupal\Core\Entity\EntityInterface[] $entities */
      $entities = \Drupal::entityTypeManager()
        ->getStorage($entity_type)
        ->loadMultiple($IDs);
      foreach ($entities as $entity) {
        $entity
          ->delete();
      }
    }
  }

  /**
   * Visits a randomly chosen entity of a specific type and (optional) bundle.
   *
   * @param string $entity_type
   *   The entity type ID.
   * @param string $bundle
   *   (optional) The bundle.
   *
   * @throws \Exception if there are no entities to visit.
   *
   * @When I visit (?:a|an) :entity_type
   * @When I visit (?:a|an) :bundle :entity_type
   */
  public function visitEntity($entity_type, $bundle = NULL) {
    $storage = \Drupal::entityTypeManager()
      ->getStorage($entity_type);
    $query = $storage
      ->getQuery();
    if ($bundle) {
      $key = $storage
        ->getEntityType()
        ->getKey('bundle');
      if ($key) {
        $query
          ->condition($key, $bundle);
      }
    }
    $items = $query
      ->execute();
    if ($items) {
      $id = reset($items);
      $url = $storage
        ->load($id)
        ->toUrl()
        ->getInternalPath();
      $this
        ->visitPath($url);
    }
    else {
      $label = $storage
        ->getEntityType()
        ->getPluralLabel();
      throw new \Exception("There are no {$bundle} {$label} available.");
    }
  }

  /**
   * Marks recently created entities to be deleted after the test scenario.
   *
   * @param string $entity_type
   *   The entity type ID.
   * @param int $n
   *   (optional) How many entities to delete.
   *
   * @When I delete the latest :entity_type
   * @When I delete the latest :entity_type entity
   * @When I delete the latest :n :entity_type entities
   */
  public function trashNewest($entity_type, $n = 1) {
    $items = \Drupal::entityTypeManager()
      ->getStorage($entity_type)
      ->getQuery()
      ->sort('created', 'DESC')
      ->range(0, $n)
      ->execute();
    foreach ($items as $id) {
      $this->trash[$entity_type][] = $id;
    }
  }

  /**
   * Counts the number of entities of a specific type and optional bundle.
   *
   * @param string $entity_type
   *   The entity type ID.
   * @param string $bundle
   *   (optional) The bundle.
   *
   * @return int
   *   How many entities exist of the given type and bundle.
   */
  protected function count($entity_type, $bundle = NULL) {
    $storage = \Drupal::entityTypeManager()
      ->getStorage($entity_type);
    $query = $storage
      ->getQuery()
      ->count();
    if ($bundle) {
      $query
        ->condition($storage
        ->getEntityType()
        ->getKey('bundle'), $bundle);
    }
    return (int) $query
      ->execute();
  }

  /**
   * Asserts that entities of a specific type and optional bundle exist.
   *
   * @param string $entity_type
   *   The entity type ID.
   * @param int $n
   *   (optional) How many entities are expected to exist.
   * @param string $bundle
   *   (optional) The bundle.
   *
   * @throws \Behat\Mink\Exception\ExpectationException if the number of
   * existing entities does not match the expected number.
   *
   * @Then 1 :entity_type entity should exist
   * @Then 1 :bundle :entity_type entity should exist
   * @Then :n :entity_type entities should exist
   * @Then :n :bundle :entity_type entities should exist
   */
  public function assertCount($entity_type, $n = 1, $bundle = NULL) {
    $count = $this
      ->count($entity_type, $bundle);
    if ($count !== (int) $n) {
      $message = sprintf('Expected %s to exist, but there are only %s.', $this
        ->formatCount($entity_type, $n), $this
        ->formatCount($entity_type, $count));
      throw new ExpectationException($message, $this
        ->getSession()
        ->getDriver());
    }
  }

  /**
   * Generates a formatted entity count string.
   *
   * @param string $entity_type
   *   The entity type ID.
   * @param int $n
   *   The number of entities.
   *
   * @see ::assertCount()
   *
   * @return string
   *   A formatted entity count string, e.g. '33 content items'.
   */
  protected function formatCount($entity_type, $n) {
    $entity_type = \Drupal::entityTypeManager()
      ->getDefinition($entity_type);
    return (string) new Plural((int) $n, '@count ' . $entity_type
      ->getSingularLabel(), '@count' . $entity_type
      ->getPluralLabel());
  }

  /**
   * Visits the edit form for an entity.
   *
   * @see lightning_dev_local_tasks_alter()
   *
   * @When I visit the edit form
   */
  public function edit() {
    $this
      ->assertSession()
      ->elementExists('named', [
      'link',
      'edit-form',
    ])
      ->click();
  }

  /**
   * Reacts when a node is created by Drupal Extension's step definition.
   *
   * @BeforeNodeCreate
   */
  public function onNodeCreate(BeforeNodeCreateScope $scope) {
    $node = $scope
      ->getEntity();
    if (!isset($node->uid)) {
      $node->uid = $this
        ->getUser();
    }
  }

  /**
   * {@inheritdoc}
   */
  protected function getUser() {
    $user = $this
      ->getUserManager()
      ->getCurrentUser();
    return $user ? $user->uid : 0;
  }

  /**
   * Visits a specific revision of a node.
   *
   * @param int $n
   *   The one-based index of the revision.
   *
   * @When /^I visit the (\d+)(?:st|nd|rd|th) revision$/
   */
  public function visitRevision($n) {
    $this
      ->assertSession()
      ->elementExists('named', [
      'link',
      'Revisions',
    ])
      ->click();
    $this
      ->getContext(ElementContext::class)
      ->click("main table tr:nth-child({$n}) td:first-child a");
  }

  /**
   * Visits the current revision of a node.
   *
   * @When I visit the current revision
   */
  public function visitCurrentRevision() {
    $this
      ->assertSession()
      ->elementExists('named', [
      'link',
      'Revisions',
    ])
      ->click();
    $session = $this
      ->getSession();

    // The revision table's selector may vary depending on whether or not Diff
    // is installed, so we need to use a pretty general selector.
    $rows = $session
      ->getPage()
      ->findAll('css', 'main table > tbody tr');

    /** @var \Behat\Mink\Element\NodeElement $row */
    foreach ($rows as $row) {
      if ($row
        ->find('css', 'td:last-child')
        ->getText() == 'Current revision') {
        return $row
          ->find('css', 'td:first-child a')
          ->click();
      }
    }

    // WTF? None of the rows were the current revision.
    throw new ExpectationException('Current revision not found.', $session
      ->getDriver());
  }

}

Members

Namesort descending Modifiers Type Description Overrides
EntityContext::$trash protected property IDs of entities created during the scenario, divided into sets keyed by entity type ID.
EntityContext::assertCount public function Asserts that entities of a specific type and optional bundle exist.
EntityContext::count protected function Counts the number of entities of a specific type and optional bundle.
EntityContext::createMultiple public function Creates a set of entities from tabular data.
EntityContext::edit public function Visits the edit form for an entity.
EntityContext::formatCount protected function Generates a formatted entity count string.
EntityContext::getUser protected function
EntityContext::onNodeCreate public function Reacts when a node is created by Drupal Extension's step definition.
EntityContext::save public function Saves an entity, ensuring automatic clean-up.
EntityContext::tearDown public function Deletes entities created during the scenario.
EntityContext::trashNewest public function Marks recently created entities to be deleted after the test scenario.
EntityContext::visitCurrentRevision public function Visits the current revision of a node.
EntityContext::visitEntity public function Visits a randomly chosen entity of a specific type and (optional) bundle.
EntityContext::visitRevision public function Visits a specific revision of a node.