mirror of
https://github.com/silverstripe/silverstripe-behat-extension
synced 2024-10-22 17:05:32 +02:00
Use FixtureFactory for YAML, move helpers to FixtureContext, consistently create assets
This commit is contained in:
parent
ea55cbfc2c
commit
fd9e84006f
@ -7,9 +7,11 @@ use Behat\Behat\Context\ClosuredContextInterface,
|
||||
Behat\Behat\Context\BehatContext,
|
||||
Behat\Behat\Context\Step,
|
||||
Behat\Behat\Event\StepEvent,
|
||||
Behat\Behat\Exception\PendingException;
|
||||
use Behat\Mink\Driver\Selenium2Driver;
|
||||
use Behat\Gherkin\Node\PyStringNode,
|
||||
Behat\Behat\Event\FeatureEvent,
|
||||
Behat\Behat\Event\ScenarioEvent,
|
||||
Behat\Behat\Exception\PendingException,
|
||||
Behat\Mink\Driver\Selenium2Driver,
|
||||
Behat\Gherkin\Node\PyStringNode,
|
||||
Behat\Gherkin\Node\TableNode;
|
||||
|
||||
// PHPUnit
|
||||
@ -28,9 +30,17 @@ class FixtureContext extends BehatContext
|
||||
*/
|
||||
protected $fixtureFactory;
|
||||
|
||||
/**
|
||||
* @var String Absolute path where file fixtures are located.
|
||||
* These will automatically get copied to their location
|
||||
* declare through the 'Given a file "..."' step defition.
|
||||
*/
|
||||
protected $filesPath;
|
||||
|
||||
protected $createdFilesPaths;
|
||||
/**
|
||||
* @var String Tracks all files and folders created from fixtures, for later cleanup.
|
||||
*/
|
||||
protected $createdFilesPaths = array();
|
||||
|
||||
public function __construct(array $parameters)
|
||||
{
|
||||
@ -47,7 +57,7 @@ class FixtureContext extends BehatContext
|
||||
*/
|
||||
public function getFixtureFactory() {
|
||||
if(!$this->fixtureFactory) {
|
||||
$this->fixtureFactory = \Injector::inst()->create('FixtureFactory', 'FixtureContextFactory');
|
||||
$this->fixtureFactory = \Injector::inst()->create('FixtureFactory', 'FixtureContextFactory');
|
||||
}
|
||||
return $this->fixtureFactory;
|
||||
}
|
||||
@ -59,6 +69,59 @@ class FixtureContext extends BehatContext
|
||||
$this->fixtureFactory = $factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String
|
||||
*/
|
||||
public function setFilesPath($path) {
|
||||
$this->filesPath = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return String
|
||||
*/
|
||||
public function getFilesPath() {
|
||||
return $this->filesPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @BeforeScenario @database-defaults
|
||||
*/
|
||||
public function beforeDatabaseDefaults(ScenarioEvent $event)
|
||||
{
|
||||
\SapphireTest::empty_temp_db();
|
||||
\DB::getConn()->quiet();
|
||||
$dataClasses = \ClassInfo::subclassesFor('DataObject');
|
||||
array_shift($dataClasses);
|
||||
foreach ($dataClasses as $dataClass) {
|
||||
\singleton($dataClass)->requireDefaultRecords();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @AfterScenario
|
||||
*/
|
||||
public function afterResetDatabase(ScenarioEvent $event)
|
||||
{
|
||||
\SapphireTest::empty_temp_db();
|
||||
}
|
||||
|
||||
/**
|
||||
* @AfterScenario
|
||||
*/
|
||||
public function afterResetAssets(ScenarioEvent $event)
|
||||
{
|
||||
if (is_array($this->createdFilesPaths)) {
|
||||
$createdFiles = array_reverse($this->createdFilesPaths);
|
||||
foreach ($createdFiles as $path) {
|
||||
if (is_dir($path)) {
|
||||
\Filesystem::removeFolder($path);
|
||||
} else {
|
||||
@unlink($path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: Given a page "Page 1"
|
||||
*
|
||||
@ -67,7 +130,13 @@ class FixtureContext extends BehatContext
|
||||
public function stepCreateRecord($type, $id)
|
||||
{
|
||||
$class = $this->convertTypeToClass($type);
|
||||
$this->fixtureFactory->createObject($class, $id);
|
||||
if(is_a($class, 'File', true)) {
|
||||
$fields = $this->prepareAsset($class, $id);
|
||||
var_dump($fields);
|
||||
} else {
|
||||
$fields = array();
|
||||
}
|
||||
$this->fixtureFactory->createObject($class, $id, $fields);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,6 +156,9 @@ class FixtureContext extends BehatContext
|
||||
$class,
|
||||
array_combine($matches['key'], $matches['value'])
|
||||
);
|
||||
if(is_a($class, 'File', true)) {
|
||||
$fields = $this->prepareAsset($class, $id, $fields);
|
||||
}
|
||||
$this->fixtureFactory->createObject($class, $id, $fields);
|
||||
}
|
||||
|
||||
@ -103,6 +175,9 @@ class FixtureContext extends BehatContext
|
||||
$class = $this->convertTypeToClass($type);
|
||||
// TODO Support more than one record
|
||||
$fields = $this->convertFields($class, $fieldsTable->getRowsHash());
|
||||
if(is_a($class, 'File', true)) {
|
||||
$fields = $this->prepareAsset($class, $id, $fields);
|
||||
}
|
||||
$this->fixtureFactory->createObject($class, $id, $fields);
|
||||
}
|
||||
|
||||
@ -174,6 +249,50 @@ class FixtureContext extends BehatContext
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^there are the following ([^\s]*) records$/
|
||||
*/
|
||||
public function stepThereAreTheFollowingRecords($dataObject, PyStringNode $string)
|
||||
{
|
||||
$yaml = array_merge(array($dataObject . ':'), $string->getLines());
|
||||
$yaml = implode("\n ", $yaml);
|
||||
|
||||
// Save fixtures into database
|
||||
// TODO Run prepareAsset() for each File and Folder record
|
||||
$yamlFixture = new \YamlFixture($yaml);
|
||||
$yamlFixture->writeInto($this->getFixtureFactory());
|
||||
}
|
||||
|
||||
protected function prepareAsset($class, $identifier, $data = null) {
|
||||
if(!$data) $data = array();
|
||||
$relativeTargetPath = (isset($data['Filename'])) ? $data['Filename'] : $identifier;
|
||||
$relativeTargetPath = preg_replace('/^' . ASSETS_DIR . '/', '', $relativeTargetPath);
|
||||
$targetPath = $this->joinPaths(ASSETS_PATH, $relativeTargetPath);
|
||||
$sourcePath = $this->joinPaths($this->getFilesPath(), basename($relativeTargetPath));
|
||||
|
||||
// Create file or folder on filesystem
|
||||
if(is_a($class, 'Folder', true)) {
|
||||
$parent = \Folder::find_or_make($relativeTargetPath);
|
||||
} else {
|
||||
if(!file_exists($sourcePath)) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
'Source file for "%s" cannot be found in "%s"',
|
||||
$targetPath,
|
||||
$sourcePath
|
||||
));
|
||||
}
|
||||
$parent = \Folder::find_or_make(dirname($relativeTargetPath));
|
||||
copy($sourcePath, $targetPath);
|
||||
}
|
||||
$data['Filename'] = $this->joinPaths(ASSETS_DIR, $relativeTargetPath);
|
||||
if(!isset($data['Name'])) $data['Name'] = basename($relativeTargetPath);
|
||||
$data['ParentID'] = $parent->ID;
|
||||
|
||||
$this->createdFilesPaths[] = $targetPath;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a natural language class description to an actual class name.
|
||||
* Respects {@link DataObject::$singular_name} variations.
|
||||
@ -188,7 +307,7 @@ class FixtureContext extends BehatContext
|
||||
|
||||
// Try direct mapping
|
||||
$class = str_replace(' ', '', ucfirst($type));
|
||||
if(class_exists($class) || !is_subclass_of($class, 'DataObject')) {
|
||||
if(class_exists($class) || !is_a($class, 'DataObject', true)) {
|
||||
return $class;
|
||||
}
|
||||
|
||||
@ -222,5 +341,14 @@ class FixtureContext extends BehatContext
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
protected function joinPaths() {
|
||||
$args = func_get_args();
|
||||
$paths = array();
|
||||
foreach($args as $arg) $paths = array_merge($paths, (array)$arg);
|
||||
foreach($paths as &$path) $path = trim($path, '/');
|
||||
if (substr($args[0], 0, 1) == '/') $paths[0] = '/' . $paths[0];
|
||||
return join('/', $paths);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -58,16 +58,8 @@ class SilverStripeContext extends MinkContext implements SilverStripeAwareContex
|
||||
*/
|
||||
protected $screenshotPath;
|
||||
|
||||
/**
|
||||
* @var FixtureFactory
|
||||
*/
|
||||
protected $fixtureFactory;
|
||||
|
||||
protected $context;
|
||||
protected $fixtures;
|
||||
protected $fixturesLazy;
|
||||
protected $filesPath;
|
||||
protected $createdFilesPaths;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes context.
|
||||
@ -136,20 +128,6 @@ class SilverStripeContext extends MinkContext implements SilverStripeAwareContex
|
||||
return $this->screenshotPath;
|
||||
}
|
||||
|
||||
public function getFixture($dataObject)
|
||||
{
|
||||
if (!array_key_exists($dataObject, $this->fixtures)) {
|
||||
throw new \OutOfBoundsException(sprintf('Data object `%s` does not exist!', $dataObject));
|
||||
}
|
||||
|
||||
return $this->fixtures[$dataObject];
|
||||
}
|
||||
|
||||
public function getFixtures()
|
||||
{
|
||||
return $this->fixtures;
|
||||
}
|
||||
|
||||
/**
|
||||
* @BeforeScenario
|
||||
*/
|
||||
@ -172,191 +150,6 @@ class SilverStripeContext extends MinkContext implements SilverStripeAwareContex
|
||||
$this->getSession()->visit($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @BeforeScenario @database-defaults
|
||||
*/
|
||||
public function beforeDatabaseDefaults(ScenarioEvent $event)
|
||||
{
|
||||
\SapphireTest::empty_temp_db();
|
||||
\DB::getConn()->quiet();
|
||||
$dataClasses = \ClassInfo::subclassesFor('DataObject');
|
||||
array_shift($dataClasses);
|
||||
foreach ($dataClasses as $dataClass) {
|
||||
\singleton($dataClass)->requireDefaultRecords();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @AfterScenario @database-defaults
|
||||
*/
|
||||
public function afterDatabaseDefaults(ScenarioEvent $event)
|
||||
{
|
||||
\SapphireTest::empty_temp_db();
|
||||
}
|
||||
|
||||
/**
|
||||
* @AfterScenario @assets
|
||||
*/
|
||||
public function afterResetAssets(ScenarioEvent $event)
|
||||
{
|
||||
if (is_array($this->createdFilesPaths)) {
|
||||
$createdFiles = array_reverse($this->createdFilesPaths);
|
||||
foreach ($createdFiles as $path) {
|
||||
if (is_dir($path)) {
|
||||
\Filesystem::removeFolder($path);
|
||||
} else {
|
||||
@unlink($path);
|
||||
}
|
||||
}
|
||||
}
|
||||
\SapphireTest::empty_temp_db();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given /^there are the following ([^\s]*) records$/
|
||||
*/
|
||||
public function thereAreTheFollowingRecords($dataObject, PyStringNode $string)
|
||||
{
|
||||
if (!is_array($this->fixtures)) {
|
||||
$this->fixtures = array();
|
||||
}
|
||||
if (!is_array($this->fixturesLazy)) {
|
||||
$this->fixturesLazy = array();
|
||||
}
|
||||
if (!isset($this->filesPath)) {
|
||||
$this->filesPath = realpath($this->getMinkParameter('files_path'));
|
||||
}
|
||||
if (!is_array($this->createdFilesPaths)) {
|
||||
$this->createdFilesPaths = array();
|
||||
}
|
||||
|
||||
if (array_key_exists($dataObject, $this->fixtures)) {
|
||||
throw new \InvalidArgumentException(sprintf('Data object `%s` already exists!', $dataObject));
|
||||
}
|
||||
|
||||
$fixture = array_merge(array($dataObject . ':'), $string->getLines());
|
||||
$fixture = implode("\n ", $fixture);
|
||||
|
||||
if ('Folder' === $dataObject) {
|
||||
$this->prepareTestAssetsDirectories($fixture);
|
||||
}
|
||||
|
||||
if ('File' === $dataObject) {
|
||||
$this->prepareTestAssetsFiles($fixture);
|
||||
}
|
||||
|
||||
$fixturesLazy = array($dataObject => array());
|
||||
if (preg_match('/=>(\w+)/', $fixture)) {
|
||||
$fixture_content = Yaml::parse($fixture);
|
||||
foreach ($fixture_content[$dataObject] as $identifier => &$fields) {
|
||||
foreach ($fields as $field_val) {
|
||||
if (substr($field_val, 0, 2) == '=>') {
|
||||
$fixturesLazy[$dataObject][$identifier] = $fixture_content[$dataObject][$identifier];
|
||||
unset($fixture_content[$dataObject][$identifier]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$fixture = Yaml::dump($fixture_content);
|
||||
}
|
||||
|
||||
// As we're dealing with split fixtures and can't join them, replace references by hand
|
||||
// if (preg_match('/=>(\w+)\.([\w.]+)/', $fixture, $matches)) {
|
||||
// if ($matches[1] !== $dataObject) {
|
||||
// $fixture = preg_replace_callback('/=>(\w+)\.([\w.]+)/', array($this, 'replaceFixtureReferences'), $fixture);
|
||||
// }
|
||||
// }
|
||||
$fixture = preg_replace_callback('/=>(\w+)\.([\w.]+)/', array($this, 'replaceFixtureReferences'), $fixture);
|
||||
// Save fixtures into database
|
||||
$this->fixtures[$dataObject] = new \YamlFixture($fixture);
|
||||
$model = \DataModel::inst();
|
||||
$this->fixtures[$dataObject]->writeInto($this->getFixtureFactory());
|
||||
// Lazy load fixtures into database
|
||||
// Loop is required for nested lazy fixtures
|
||||
foreach ($fixturesLazy[$dataObject] as $identifier => $fields) {
|
||||
$fixture = array(
|
||||
$dataObject => array(
|
||||
$identifier => $fields,
|
||||
),
|
||||
);
|
||||
$fixture = Yaml::dump($fixture);
|
||||
$fixture = preg_replace_callback('/=>(\w+)\.([\w.]+)/', array($this, 'replaceFixtureReferences'), $fixture);
|
||||
$this->fixturesLazy[$dataObject][$identifier] = new \YamlFixture($fixture);
|
||||
$this->fixturesLazy[$dataObject][$identifier]->writeInto($this->getFixtureFactory());
|
||||
}
|
||||
}
|
||||
|
||||
protected function prepareTestAssetsDirectories($fixture)
|
||||
{
|
||||
$folders = Yaml::parse($fixture);
|
||||
foreach ($folders['Folder'] as $fields) {
|
||||
foreach ($fields as $field => $value) {
|
||||
if ('Filename' === $field) {
|
||||
if (0 === strpos($value, 'assets/')) {
|
||||
$value = substr($value, strlen('assets/'));
|
||||
}
|
||||
|
||||
$folder_path = ASSETS_PATH . DIRECTORY_SEPARATOR . $value;
|
||||
if (file_exists($folder_path) && !is_dir($folder_path)) {
|
||||
throw new \Exception(sprintf('`%s` already exists and is not a directory', $this->filesPath));
|
||||
}
|
||||
|
||||
\Filesystem::makeFolder($folder_path);
|
||||
$this->createdFilesPaths[] = $folder_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function prepareTestAssetsFiles($fixture)
|
||||
{
|
||||
$files = Yaml::parse($fixture);
|
||||
foreach ($files['File'] as $fields) {
|
||||
foreach ($fields as $field => $value) {
|
||||
if ('Filename' === $field) {
|
||||
if (0 === strpos($value, 'assets/')) {
|
||||
$value = substr($value, strlen('assets/'));
|
||||
}
|
||||
|
||||
$filePath = $this->filesPath . DIRECTORY_SEPARATOR . basename($value);
|
||||
if (!file_exists($filePath) || !is_file($filePath)) {
|
||||
throw new \Exception(sprintf('`%s` does not exist or is not a file', $this->filesPath));
|
||||
}
|
||||
$asset_path = ASSETS_PATH . DIRECTORY_SEPARATOR . $value;
|
||||
if (file_exists($asset_path) && !is_file($asset_path)) {
|
||||
throw new \Exception(sprintf('`%s` already exists and is not a file', $this->filesPath));
|
||||
}
|
||||
|
||||
if (!file_exists($asset_path)) {
|
||||
if (@copy($filePath, $asset_path)) {
|
||||
$this->createdFilesPaths[] = $asset_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function replaceFixtureReferences($references)
|
||||
{
|
||||
if (!array_key_exists($references[1], $this->fixtures)) {
|
||||
throw new \OutOfBoundsException(sprintf('Data object `%s` does not exist!', $references[1]));
|
||||
}
|
||||
return $this->idFromFixture($references[1], $references[2]);
|
||||
}
|
||||
|
||||
protected function idFromFixture($className, $identifier)
|
||||
{
|
||||
if (false !== ($id = $this->getFixtureFactory()->getId($className, $identifier))) {
|
||||
return $id;
|
||||
}
|
||||
if (isset($this->fixturesLazy[$className], $this->fixturesLazy[$className][$identifier]) &&
|
||||
false !== ($id = $this->fixturesLazy[$className][$identifier]->idFromFixture($className, $identifier))) {
|
||||
return $id;
|
||||
}
|
||||
|
||||
throw new \OutOfBoundsException(sprintf('`%s` identifier in Data object `%s` does not exist!', $identifier, $className));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses given URL and returns its components
|
||||
*
|
||||
@ -419,15 +212,6 @@ class SilverStripeContext extends MinkContext implements SilverStripeAwareContex
|
||||
return $this->getMinkParameter('base_url') ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FixtureFactory
|
||||
*/
|
||||
public function getFixtureFactory()
|
||||
{
|
||||
if(!$this->fixtureFactory) $this->fixtureFactory = \Injector::inst()->create('FixtureFactory');
|
||||
return $this->fixtureFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins URL parts into an URL using forward slash.
|
||||
* Forward slash usages are normalised to one between parts.
|
||||
|
Loading…
Reference in New Issue
Block a user