You are here

final class EntityContext in Lightning Core 8.3

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.2 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 is an internal part of Lightning Core's testing system and may be changed or removed at any time without warning. It should not be extended, instantiated, or used in any way by external code! If you need to use this functionality, you should copy the relevant code into your own project.

Hierarchy

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

Expanded class hierarchy of EntityContext

File

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

Namespace

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

  /**
   * IDs of entities created during the scenario.
   *
   * The IDs are divided into groups, keyed by entity type ID.
   *
   * @var array
   */
  private $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
      ->getCurrentUserUid();
    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.
   */
  private 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'.
   */
  private 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
        ->getCurrentUserUid();
    }
  }

  /**
   * Gets the current user's UID.
   *
   * @return int
   *   Returns the current user's UID if there is one or 0 if not.
   */
  protected function getCurrentUserUid() {
    $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 private property IDs of entities created during the scenario.
EntityContext::assertCount public function Asserts that entities of a specific type and optional bundle exist.
EntityContext::count private 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 private function Generates a formatted entity count string.
EntityContext::getCurrentUserUid protected function Gets the current user's UID.
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.