View source
<?php
namespace Acquia\LightningExtension\Context;
use Behat\Behat\Hook\Scope\ScenarioScope;
use Behat\Mink\Driver\Selenium2Driver;
use Behat\Mink\Element\DocumentElement;
use Behat\Mink\Exception\ElementNotFoundException;
use Behat\Mink\Exception\ExpectationException;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Html;
use Drupal\DrupalExtension\Context\DrupalSubContextBase;
use Webmozart\Assert\Assert;
final class EntityBrowserContext extends DrupalSubContextBase {
use AwaitTrait;
private $isJS;
public function setUp(ScenarioScope $scope) {
$tags = array_merge($scope
->getScenario()
->getTags(), $scope
->getFeature()
->getTags());
$this->isJS = in_array('javascript', $tags, TRUE);
}
private 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]');
}
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();
}
}
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());
}
}
public function submit() {
$session = $this
->getSession();
$button = $this
->assertSession()
->elementExists('css', '[data-drupal-selector="edit-submit"]')
->getXpath();
$frame = $session
->evaluateScript('window.name') ?: $session
->evaluateScript('window.active_iframe.name');
Assert::notEmpty($frame);
$session
->switchToIFrame();
if ($session
->getDriver() instanceof Selenium2Driver) {
$button = addslashes($button);
}
$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();
}
public function open($id) {
$this->isJS ? $this
->openJs($id) : $this
->openNoJs($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}";
$session = $this
->getSession();
Assert::true($session
->wait(10000, $frame));
Assert::true($session
->wait(10000, "{$frame}.document.readyState === 'complete'"));
}
private function openNoJs($id) {
$settings = $this
->getEntityBrowserSettings($id);
Assert::notEmpty($settings['src']);
$this
->visitPath($settings['src']);
}
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);
}
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;
}
private function getAllSettings() {
$settings = $this
->assertSession()
->elementExists('css', 'script[type="application/json"][data-drupal-selector="drupal-settings-json"]')
->getText();
return Json::decode($settings);
}
public function selectItems($count, $id) {
$this->isJS ? $this
->switchJs($id) : $this
->switchNoJs($id);
$this
->getSession()
->getPage()
->clickLink('Library');
$this
->awaitAjax();
for ($n = 0; $n < $count; $n++) {
$this
->select($n + 1);
}
$this
->submit();
$this
->awaitAjax();
}
private function switchJs($id) {
$session = $this
->getSession();
$page = $session
->getPage();
$page
->pressButton('Add media');
$selector = 'iframe[name="entity_browser_iframe_' . $id . '"]';
$frame = $page
->waitFor(30, function (DocumentElement $page) use ($selector) {
return $page
->find('css', $selector);
});
if ($page) {
$session
->switchToIFrame($frame
->getAttribute('id'));
}
else {
throw new ElementNotFoundException($session
->getDriver(), 'frame', 'css', $selector);
}
}
private function switchNoJs($id) {
$settings = $this
->getEntityBrowserSettings($id);
Assert::notEmpty($settings['src']);
$this
->visitPath($settings['src']);
}
}