Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rehash file context #28

Open
wants to merge 3 commits into
base: drupal8-file
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 190 additions & 31 deletions src/Palantirnet/PalantirBehatExtension/Context/DrupalFileContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
namespace Palantirnet\PalantirBehatExtension\Context;

use Behat\Gherkin\Node\TableNode;
use Palantirnet\PalantirBehatExtension\NotUpdatedException;
use Behat\Mink\Element\NodeElement;
use Drupal;
use Drupal\file\Entity\File;
use Drupal\DrupalExtension\Hook\Scope\EntityScope;
use PHPUnit_Framework_Assert as Assert;

/**
* Behat context class with additional file-related steps.
Expand All @@ -19,60 +22,216 @@ class DrupalFileContext extends SharedDrupalContext


/**
* Create a Drupal file record.
* Register fields which hold files so we can grab the fid on node save.
*
* @Given the file :filename
* @var array File fields used in this context.
*/
protected $fileFields = [];

/**
* Keep track of files so they can be cleaned up.
*
* @param string $filename The name of a file within the MinkExtension's files_path directory.
* @param int $status FILE_STATUS_PERMANENT or 0 if the file is temporary. Defaults to FILE_STATUS_PERMANENT.
* @var array
*/
protected $files = [];

/**
* Get the files managed in this context.
* @return array
*/
public function getFiles()
{
return $this->files;
}//end getFiles()


/**
* Add a file to manage.
*
* @return void
* @param string $filename The name of the file to manage.
* @param File $file The file to manage.
*
* @return $this
*/
public function createFile($filename, $status = FILE_STATUS_PERMANENT)
public function addFile($filename, File $file)
{

$file = new File(array(), 'file');
$file->setFilename($filename);
$file->set('status', $status);
$this->files[$filename] = $file->id();

return $this;

}//end addFile()

/**
* Add a file based on file id. Looks up the filename if not passed.
*
* @param int $fid The file id.
* @param string $filename [optional] The name of the file.
*
* @return $this
*/
public function addFileById($fid, $filename = '')
{

$file = $this->expandFile($file);
$filename = $filename ?: File::load($fid)->getFilename();
$this->files[$filename] = $fid;

$this->fileCreate($file);
return $this;

}//end createFile()
}//end addFileById()


/**
* Create a set of Drupal file records.
* Get a specific file from the managed files.
*
* @Given files:
* @param String $filename Original name of the file to get from behat step.
*
* Given files:
* | filename | status | author |
* | example.pdf | 1 | Somebody |
* | test.png | 0 | Admin |
* | ... | ... | ... |
* @return File
*/
public function getFile($filename)
{
return File::load($this->files[$filename]);
}//end getFile()


/**
* Get the fields which may hold files.
*
* @param TableNode $filesTable A hash of file property objects.
* @return array
*/
public function getFileFields()
{
return $this->fileFields;
}//end getFileFields()


/**
* Add a field which may hold files.
*
* @return void
* @param String $filename Original name of the file to get from behat step.
* @param String $fileField The field machine name.
*
* @return DrupalFileContext $this
*/
public function createFiles(TableNode $filesTable)
public function addFileField($filename, $fileField)
{
$this->fileFields[$filename] = $fileField;
return $this;
}//end addFileField()

foreach ($filesTable->getHash() as $fileHash) {
$file = new File(array(), 'file');
$file->setFilename($fileHash['filename']);

$status = isset($fileHash['status']) ?: FILE_STATUS_PERMANENT;
$file->set('status', $status);
/**
* Replace file fields in an entity.
*
* @beforeNodeCreate
*
* @param EntityScope $scope The BeforeNodeCreateScope for this hook.
*
* @return \stdClass
*/
public function replaceFiles(EntityScope $scope)
{
$fields = (array) $scope->getEntity();
$node = $scope->getEntity();
$prefix = 'file: {';
foreach ($fields as $fieldname => $file) {
if (TRUE === is_string($file) && 0 === strpos($file, $prefix)) {
$filename = substr($file, strlen($prefix), strlen($file) - strlen($prefix) - 1);
$this->addFileField($filename, $fieldname);
$node->$fieldname = rtrim(realpath($this->getMinkParameter('files_path')), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$filename;
}
}
}//end replaceFiles()


$file = $this->expandFile($file);
/**
* Register files created on node create so we can delete them later.
*
* @afterNodeCreate
*
* @param EntityScope $scope The AfterNodeCreateScope of this hook.
*
* @return null
*/
public function registerFiles(EntityScope $scope)
{

$this->fileCreate($file);
$node = $scope->getEntity();
foreach ($this->getFileFields() as $filename => $field) {
$value = $node->{$field};
$this->addFileById($value['target_id'], $filename);
}

}//end createFiles()
}//end registerFiles()


/**
* Assert an image is displayed on the page.
*
* @Then I should see the image :filename
*
* @param String $filename The filename of the image we expect to find.
*
* @return bool
*
* @throws \Exception
*/
public function assertImage($filename)
{

// @var File $file
$file = $this->getFile($filename);
$filename = $file->getFilename();

$imageElements = $this->getSession()->getPage()->findAll('css', 'img');
$found = false;

// @var NodeElement $image
foreach ($imageElements as $image) {
$imageUrl = $image->getAttribute('src');
$imageFilename = basename(parse_url($imageUrl, PHP_URL_PATH));


if ($imageFilename === $filename) {
$found = true;
$this->getSession()->visit($imageUrl);
$statusCode = $this->getSession()->getStatusCode();
$message = "Expected to find the image, $filename at $imageUrl. Got status code: {$statusCode}.";
Assert::assertEquals("200", $statusCode, $message);
}
}

Assert::assertTrue($found, "Could not find image: $filename");
}//end assertImage()



/**
* Remove any created files.
*
* @AfterScenario
*
* @return void
*/
public function cleanFiles()
{
$files = array_map(
function ($filename) {
return $this->getFile($filename);
},
array_keys($this->files)
);

$manager = Drupal::entityTypeManager()->getStorage('file');
@$manager->delete($files);

foreach ($files as $filename => $file) {
$file->delete();
}

$this->files = [];

}//end cleanFiles()


}//end class
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class DrupalSetupContext extends SharedDrupalContext
*/
public function assertDrupal()
{
throw new NotUpdatedException();

if ($this->getDriver()->isBootstrapped() === false) {
throw new \Exception('The Drupal site is not bootstrapped.');
Expand Down
110 changes: 3 additions & 107 deletions src/Palantirnet/PalantirBehatExtension/Context/SharedDrupalContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@

namespace Palantirnet\PalantirBehatExtension\Context;

use Behat\Gherkin\Node\TableNode;
use Drupal\DrupalExtension\Context\RawDrupalContext;
use Palantirnet\PalantirBehatExtension\NotUpdatedException;
use Drupal\DrupalExtension\Hook\Scope\EntityScope;
use Drupal\file\Entity\File;
use Palantirnet\PalantirBehatExtension\NotUpdatedException;

/**
* Behat context class with functionality that is shared across custom contexts.
Expand Down Expand Up @@ -153,110 +155,4 @@ public function findUserByName($userName)
}//end findUserByName()


/**
* Save a file.
*
* @param stdclass $file A simple object representing file data.
* Properties should be scalar values, and files may use either the 'uid' or
* 'author' fields to attribute the file to a particular Drupal user.
*
* @return stdclass
* A Drupal file object.
*/
public function fileCreate($file)
{
// Save the file and overwrite if it already exists.
$dest = file_build_uri(drupal_basename($file->GetFileUri()));
$result = file_copy($file, $dest, FILE_EXISTS_REPLACE);

// Stash the file object for later cleanup.
if (empty($result->id()) === false) {
$this->files[] = $result;
} else {
throw new \Exception(sprintf('File "%s" could not be copied from "%s" to "%s".', $file->getFilename(), $file->GetFileUri(), $result->GetFileUri()));
}

return $result;

}//end fileCreate()


/**
* Add required file properties.
*
* @param stdclass $file A simple object representing file data. The 'filename'
* property is required.
*
* @return stdclass
* A file object with at least the filename, uri, uid, and status
* properties.
*/
public function expandFile($file)
{
if (empty($file->getFilename()) === true) {
throw new \Exception("Can't create file with no source filename; this should be the name of a file within the MinkExtension's files_path directory.");
}

// Set the URI to the path to the file within the MinkExtension's
// files_path parameter.
$file->setFileUri(rtrim(realpath($this->getMinkParameter('files_path')), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$file->getFilename());

$file->set('langcode', $file->language()->getId());

$file->setChangedTime(time());

// Assign authorship if none exists and `author` is passed.
/*
if (isset($file->getOwnerId()) === false && empty($file->author) === false) {
$account = user_load_by_name($file->author);
if ($account !== false) {
$file->uid = $account->uid;
}
}

Add default values.
$defaults = array(
'uid' => 0,
'status' => 1,
);

foreach ($defaults as $key => $default) {
if (isset($file->$key) === false) {
$file->$key = $default;
}
} */

return $file;

}//end expandFile()


/**
* Keep track of files so they can be cleaned up.
*
* @var array
*/
protected $files = array();


/**
* Remove any created files.
*
* @AfterScenario
*
* @return void
*/
public function cleanFiles()
{
throw new NotUpdatedException();

foreach ($this->files as $file) {
file_delete($file, true);
}

$this->files = array();

}//end cleanFiles()


}//end class