EntityBrowserContext.behat.inc in Lightning Media 8.2
Same filename and directory in other branches
Namespace
Acquia\LightningExtension\ContextFile
tests/contexts/EntityBrowserContext.behat.incView source
<?php
namespace Acquia\LightningExtension\Context;
use Behat\Behat\Hook\Scope\ScenarioScope;
use Behat\Mink\Exception\ExpectationException;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Html;
use Drupal\DrupalExtension\Context\DrupalSubContextBase;
use Webmozart\Assert\Assert;
/**
* Contains step definitions for interacting with entity browser instances.
*
* @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 Media 3.x.
*/
class EntityBrowserContext extends DrupalSubContextBase {
use AwaitTrait;
/**
* Indicates if the current scenario uses JavaScript.
*
* @var bool
*/
private $isJS;
/**
* Performs pre-scenario tasks.
*
* @BeforeScenario
*/
public function setUp(ScenarioScope $scope) {
// Check if the feature or scenario has the 'javascript' tag.
$tags = array_merge($scope
->getScenario()
->getTags(), $scope
->getFeature()
->getTags());
$this->isJS = in_array('javascript', $tags, TRUE);
}
/**
* Gets all items in an entity browser.
*
* @param string $browser_id
* (optional) The entity browser ID.
*
* @return \Behat\Mink\Element\NodeElement[]
* An array of items in the entity browser.
*/
protected function getItems($browser_id = NULL) {
if ($browser_id) {
$selector = 'form#entity-browser-' . Html::cleanCssIdentifier($browser_id) . '-form';
}
else {
$selector = 'form[data-entity-browser-uuid]';
}
return $this
->assertSession()
->elementExists('css', $selector)
->findAll('css', '[data-selectable]');
}
/**
* Selects an item in an entity browser view.
*
* @param int $n
* The one-based index of the item to select.
* @param string $browser_id
* (optional) The entity browser ID.
*
* @throws \Behat\Mink\Exception\ExpectationException if the entity browser
* contains fewer than $n items.
*
* @When I select item :n
* @When I select item :n from the entity browser
* @When I select item :n from the :browser_id entity browser
*/
public function select($n, $browser_id = NULL) {
$items = $this
->getItems($browser_id);
if ($n > count($items)) {
throw new ExpectationException("Expected at least {$n} item(s) in the {$browser_id} entity browser.", $this
->getSession()
->getDriver());
}
else {
$items[--$n]
->click();
}
}
/**
* Asserts that a certain number of items are visible in the entity browser.
*
* @param int $n
* The number of items that should be visible.
* @param string $browser_id
* (optional) The entity browser ID.
*
* @throws ExpectationException if the actual number of items in the entity
* browser does not match the expected number.
*
* @Then I should see :n item(s) in the entity browser
*/
public function assertCount($n, $browser_id = NULL) {
$count = count($this
->getItems($browser_id));
if ($count !== (int) $n) {
throw new ExpectationException("Expected {$n} items in the {$browser_id} entity browser, but there were {$count}.", $this
->getSession()
->getDriver());
}
}
/**
* Clicks on a tab with the specified text in an active entity browser and
* waits for it to load.
*
* @param string $tab
* The text of the tab to switch to.
*
* @When I switch to the :tab Entity Browser tab
*/
public function switchToEBTab($tab) {
$this
->assertSession()
->elementExists('css', 'nav.eb-tabs')
->clickLink($tab);
// I don't see any way to assert the tab specifically has loaded. So,
// instead we just wait a reasonable amount of time.
sleep(5);
}
/**
* Submits the entity browser.
*
* @When I submit the entity browser
*/
public function submit() {
$session = $this
->getSession();
// @TODO: Make this smarter, because we can't be sure that #edit-submit
// exists at all, or that it's the correct submit button.
$button = $this
->assertSession()
->elementExists('css', '#edit-submit')
->getXpath();
$frame = $session
->evaluateScript('window.name') ?: $session
->evaluateScript('window.active_iframe.name');
assert(!empty($frame));
// Switch out of the iFrame, because it will be destroyed as soon as we
// press the button.
$session
->switchToIFrame();
$js = <<<END
document.evaluate('{<span class="php-variable">$button</span>}', window.{<span class="php-variable">$frame</span>}.document, null).iterateNext().click();
END;
$session
->executeScript($js);
$this
->awaitAjax();
}
/**
* Opens an entity browser.
*
* @param string $id
* The entity browser ID.
*/
public function open($id) {
$this->isJS ? $this
->openJS($id) : $this
->openNoJS($id);
}
/**
* Opens an entity browser using JavaScript.
*
* @param string $id
* The entity browser ID.
*/
private function openJS($id) {
$settings = $this
->getEntityBrowserSettings($id);
$this
->assertSession()
->elementExists('css', '.entity-browser-handle[data-uuid="' . $settings['uuid'] . '"]')
->click();
$frame = "window.entity_browser_iframe_{$id}";
$this
->awaitExpression($frame);
$this
->awaitExpression("{$frame}.document.readyState === 'complete'");
}
/**
* Opens an entity browser without using JavaScript.
*
* @param string $id
* The entity browser ID.
*/
private function openNoJS($id) {
$settings = $this
->getEntityBrowserSettings($id);
Assert::notEmpty($settings['src']);
$this
->visitPath($settings['src']);
}
/**
* Returns settings for a single entity browser.
*
* @param string $id
* The entity browser ID (not UUID).
*
* @return array
* The settings for the entity browser.
*
* @throws \Exception
* If there is not exactly one entity browser with the given ID.
*/
private function getEntityBrowserSettings($id) {
$filter = function (array $settings) use ($id) {
return $settings['entity_browser_id'] === $id;
};
$settings = array_filter($this
->getAllEntityBrowserSettings(), $filter);
Assert::count($settings, 1);
return reset($settings);
}
/**
* Returns settings for all entity browser instances on the page.
*
* @return array[]
* The settings for all entity browser instances, keyed by UUID.
*/
private function getAllEntityBrowserSettings() {
$settings = $this
->getAllSettings();
Assert::isArray($settings['entity_browser']);
Assert::notEmpty($settings['entity_browser']);
$display_types = \Drupal::service('plugin.manager.entity_browser.display')
->getDefinitions();
$settings = array_intersect_key($settings['entity_browser'], $display_types);
$all = [];
foreach ($settings as $display_type => $instances) {
foreach ($instances as $uuid => $instance) {
$instance['display_type'] = $display_type;
$instance['uuid'] = $uuid;
$all[$uuid] = $instance;
}
}
return $all;
}
/**
* Returns all Drupal JavaScript settings on the page.
*
* @return mixed[]
* The decoded settings.
*/
private function getAllSettings() {
$settings = $this
->assertSession()
->elementExists('css', 'script[type="application/json"][data-drupal-selector="drupal-settings-json"]')
->getText();
return Json::decode($settings);
}
}
Classes
Name![]() |
Description |
---|---|
EntityBrowserContext | Contains step definitions for interacting with entity browser instances. |