EntityContext.behat.inc in Lightning Core 8
Same filename and directory in other branches
Namespace
Acquia\LightningExtension\ContextFile
tests/contexts/EntityContext.behat.incView source
<?php
namespace Acquia\LightningExtension\Context;
use Behat\Gherkin\Node\TableNode;
use Behat\Mink\Exception\ExpectationException;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\StringTranslation\PluralTranslatableMarkup as Plural;
use Drupal\DrupalExtension\Context\DrupalSubContextBase;
use Drupal\DrupalExtension\Hook\Scope\BeforeNodeCreateScope;
use Drupal\user\EntityOwnerInterface;
/**
* Contains miscellaneous step definitions for working with Drupal entities.
*/
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());
}
}
Classes
Name | Description |
---|---|
EntityContext | Contains miscellaneous step definitions for working with Drupal entities. |