Created
June 28, 2017 20:52
-
-
Save kerasai/d40ebaef6854b9938759a174327b4d23 to your computer and use it in GitHub Desktop.
Behat context for working with files in Drupal 8.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use Behat\Gherkin\Node\PyStringNode; | |
use Behat\Mink\Element\NodeElement; | |
use Behat\Mink\Mink; | |
use Behat\MinkExtension\Context\MinkAwareContext; | |
/** | |
* Class FileContext. | |
*/ | |
class FileContext implements MinkAwareContext { | |
/** | |
* Files created by this context. | |
* | |
* @var \Drupal\file\Entity\File[] | |
*/ | |
protected $files = []; | |
/** | |
* Mink parameters. | |
* | |
* @var \Behat\Mink\Mink | |
*/ | |
protected $mink; | |
/** | |
* Mink instance. | |
* | |
* @var array | |
*/ | |
protected $minkParameters = []; | |
/** | |
* Working dir for the Behat process. | |
* | |
* @var string | |
*/ | |
protected $workingDir; | |
/** | |
* Prepares test folders in the temporary directory. | |
* | |
* @BeforeScenario | |
*/ | |
public function prepare() { | |
$this->workingDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'behat' . DIRECTORY_SEPARATOR . md5(microtime() * rand(0, 10000)); | |
} | |
/** | |
* Prepares test folders in the temporary directory. | |
* | |
* @AfterScenario | |
*/ | |
public function cleanup() { | |
foreach ($this->files as $file) { | |
$file->delete(); | |
} | |
$this->files = []; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function setMink(Mink $mink) { | |
$this->mink = $mink; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function setMinkParameters(array $parameters) { | |
$this->minkParameters = $parameters; | |
} | |
/** | |
* Creates a file with specified name and context in current workdir. | |
* | |
* @Given /^(?:there is )?a file named "([^"]*)" with:$/ | |
* | |
* @param string $filename | |
* Name of the file (relative path) | |
* @param PyStringNode $content | |
* File content. | |
*/ | |
public function assertFileNamed($filename, PyStringNode $content) { | |
$content = strtr((string) $content, array("'''" => '"""')); | |
$this->createFile($this->workingDir . '/' . $filename, $content); | |
} | |
/** | |
* Create a file. | |
* | |
* @param string $filename | |
* Name of the file. | |
* @param string $content | |
* File content. | |
*/ | |
private function createFile($filename, $content) { | |
$path = dirname($filename); | |
if (!is_dir($path)) { | |
mkdir($path, 0777, true); | |
} | |
file_put_contents($filename, $content); | |
} | |
/** | |
* Selects files for entity browser. | |
* | |
* @When I select :file entity for :field | |
* @When I select :file entity for :field with alt :alt | |
* @When I select :file entity for :field with description :desc | |
*/ | |
public function assertEntityFromFile($file, $field, $alt = NULL, $desc = NULL) { | |
// Unfortunately ::findField does not seem to work on hidden inputs, so | |
// we'll look for the input by name. | |
$name = $field . '[target_id]'; | |
$fieldEl = $this->mink->getSession()->getPage()->find('css', 'input[name="' . $name . '"]'); | |
if (!$fieldEl) { | |
throw new \Exception(sprintf('Unable to find field "%s".', $field)); | |
} | |
// Create an entity for the file. | |
$source = $this->workingDir . '/' . $file; | |
$dest = "public://behat/$file"; | |
$dir = dirname($dest); | |
file_prepare_directory($dir, FILE_CREATE_DIRECTORY); | |
$file = file_save_data(file_get_contents($source), $dest, FILE_EXISTS_RENAME); | |
if (!$file) { | |
throw new \Exception(sprintf('Unable to save file "%s".', $dest)); | |
} | |
$this->files[] = $file; | |
$file->save(); | |
// Add the entity to the field value. | |
$value = array_filter(array_map('trim', explode(' ', $fieldEl->getValue()))); | |
$value[] = "file:{$file->id()}"; | |
$fieldEl->setValue(implode(' ', $value)); | |
$weightName = $field . '[current][' . $file->id() .'][_weight]'; | |
$weightEl = $this->mink->getSession()->getPage()->find('css', 'input[name="' . $weightName . '"]'); | |
if ($weightEl) { | |
$weightEl->setValue(0); | |
} | |
else { | |
$this->createEntityBrowserInputNode($fieldEl, $weightName, 0); | |
} | |
// Create the "alt" input if specified. | |
if ($alt) { | |
$altName = $field . '[current][' . $file->id() .'][meta][alt]'; | |
$altEl = $this->mink->getSession()->getPage()->find('css', 'input[name="' . $altName . '"]'); | |
if ($altEl) { | |
$altEl->setValue($alt); | |
} | |
else { | |
$this->createEntityBrowserInputNode($fieldEl, $altName, $alt); | |
} | |
} | |
// Create the "desc" input if specified. | |
if ($desc) { | |
$descName = $field . '[current][' . $file->id() .'][meta][description]'; | |
$descEl = $this->mink->getSession()->getPage()->find('css', 'input[name="' . $descName . '"]'); | |
if ($descEl) { | |
$descEl->setValue($desc); | |
} | |
else { | |
$this->createEntityBrowserInputNode($fieldEl, $descName, $desc); | |
} | |
} | |
} | |
/** | |
* Inserts a DOMNode into the form to mimic entity browser input. | |
* | |
* Likely only works when utilizing the GoutteDriver. | |
* | |
* @param \Behat\Mink\Element\NodeElement $fieldEl | |
* The entity browser field element. | |
* @param string $inputName | |
* The name of the node. | |
* @param string $value | |
* The value to set on the node. | |
*/ | |
protected function createEntityBrowserInputNode(NodeElement $fieldEl, $inputName, $value) { | |
/** @var \Behat\Mink\Driver\GoutteDriver $driver */ | |
$driver = $this->mink->getSession()->getDriver(); | |
$client = $driver->getClient(); | |
$crawler = $client->getCrawler(); | |
/** @var \DOMDocument $doc */ | |
$doc = $crawler->getNode(0)->ownerDocument; | |
$node = $doc->createElement('input'); | |
$node->setAttribute('type', 'hidden'); | |
$node->setAttribute('name', $inputName); | |
$node->setAttribute('value', $value); | |
$query = new \DOMXPath($doc); | |
$result = $query->query($fieldEl->getXpath())->item(0); | |
$result->insertBefore($node); | |
} | |
/** | |
* Produces a Fill Murray placeholder image. | |
* | |
* @param string $size | |
* Size of the image in pixels, ie. "800 , 600". | |
* | |
* @Given there is a Fill Murray image :size | |
*/ | |
public function assertFillMurray($size) { | |
$dimensions = array_map('trim', explode(',', $size)); | |
$fileName = 'fm_' . implode('_', $dimensions) . '.jpg'; | |
// Check temp space, to avoid re-downloading on subsequent scenarios. | |
$temp = '/tmp/behat/fm/' . $fileName; | |
if (!file_exists($temp)) { | |
$dir = dirname($temp); | |
if (!is_dir($dir)) { | |
@mkdir($dir, 0777, TRUE); | |
} | |
$url = 'https://www.fillmurray.com/' . implode('/', $dimensions); | |
$contents = file_get_contents($url); | |
file_put_contents($temp, $contents); | |
} | |
$contents = file_get_contents($temp); | |
$this->createFile($this->workingDir . '/' . $fileName, $contents); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment