From e7cc08f6ae6b28482c6f69ae32253efcc01028b2 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Wed, 5 Jun 2013 13:28:57 +0200 Subject: [PATCH 1/4] Behat: Auto-publishing SiteTree fixtures, RedirectorPage fixtures They can be unpublished through an explicit step. Extending from base FeatureContext in order to easily share the same FixtureFactory but still add new blueprints to it. --- .../features/bootstrap/FeatureContext.php | 28 +++-- .../Cms/Test/Behaviour/FixtureContext.php | 110 ++++++++++++++++++ 2 files changed, 131 insertions(+), 7 deletions(-) create mode 100644 tests/behat/features/bootstrap/SilverStripe/Cms/Test/Behaviour/FixtureContext.php diff --git a/tests/behat/features/bootstrap/FeatureContext.php b/tests/behat/features/bootstrap/FeatureContext.php index f9acec3d..1f9e5bc1 100644 --- a/tests/behat/features/bootstrap/FeatureContext.php +++ b/tests/behat/features/bootstrap/FeatureContext.php @@ -5,8 +5,10 @@ namespace SilverStripe\Cms\Test\Behaviour; use SilverStripe\BehatExtension\Context\SilverStripeContext, SilverStripe\BehatExtension\Context\BasicContext, SilverStripe\BehatExtension\Context\LoginContext, + SilverStripe\BehatExtension\Context\FixtureContext, SilverStripe\Framework\Test\Behaviour\CmsFormsContext, - SilverStripe\Framework\Test\Behaviour\CmsUiContext; + SilverStripe\Framework\Test\Behaviour\CmsUiContext, + SilverStripe\Cms\Test\Behaviour; // PHPUnit require_once 'PHPUnit/Autoload.php'; @@ -18,7 +20,7 @@ require_once 'PHPUnit/Framework/Assert/Functions.php'; * Context automatically loaded by Behat. * Uses subcontexts to extend functionality. */ -class FeatureContext extends SilverStripeContext +class FeatureContext extends \SilverStripe\Framework\Test\Behaviour\FeatureContext { /** * Initializes context. @@ -28,11 +30,23 @@ class FeatureContext extends SilverStripeContext */ public function __construct(array $parameters) { - $this->useContext('BasicContext', new BasicContext($parameters)); - $this->useContext('LoginContext', new LoginContext($parameters)); - $this->useContext('CmsFormsContext', new CmsFormsContext($parameters)); - $this->useContext('CmsUiContext', new CmsUiContext($parameters)); - parent::__construct($parameters); + + // Override existing fixture context with more specific one + $fixtureContext = new \SilverStripe\Cms\Test\Behaviour\FixtureContext($parameters); + $fixtureContext->setFixtureFactory($this->getFixtureFactory()); + $this->useContext('FixtureContext', $fixtureContext); + + // Use blueprints which auto-publish all subclasses of SiteTree + $factory = $fixtureContext->getFixtureFactory(); + foreach(\ClassInfo::subclassesFor('SiteTree') as $id => $class) { + $blueprint = \Injector::inst()->create('FixtureBlueprint', $class); + $blueprint->addCallback('afterCreate', function($obj, $identifier, &$data, &$fixtures) { + $obj->publish('Stage', 'Live'); + }); + $factory->define($class, $blueprint); + } + } + } diff --git a/tests/behat/features/bootstrap/SilverStripe/Cms/Test/Behaviour/FixtureContext.php b/tests/behat/features/bootstrap/SilverStripe/Cms/Test/Behaviour/FixtureContext.php new file mode 100644 index 00000000..58572fb1 --- /dev/null +++ b/tests/behat/features/bootstrap/SilverStripe/Cms/Test/Behaviour/FixtureContext.php @@ -0,0 +1,110 @@ +context = $parameters; + } + + public function getSession($name = null) + { + return $this->getMainContext()->getSession($name); + } + + /** + * @return \FixtureFactory + */ + public function getFixtureFactory() { + if(!$this->fixtureFactory) { + $this->fixtureFactory = \Injector::inst()->get('FixtureFactory', 'FixtureContextFactory'); + } + return $this->fixtureFactory; + } + + /** + * @param \FixtureFactory $factory + */ + public function setFixtureFactory(\FixtureFactory $factory) { + $this->fixtureFactory = $factory; + } + + /** + * Find or create a redirector page and link to another existing page. + * Example: Given a page "My Redirect" which redirects to a page "Page 1" + * + * @Given /^(?:(an|a|the) )(?[^"]+)"(?[^"]+)" (:?which )?redirects to (?:(an|a|the) )(?[^"]+)"(?[^"]+)"$/ + */ + public function stepCreateRedirectorPage($type, $id, $targetType, $targetId) + { + $class = 'RedirectorPage'; + $targetClass = $this->convertTypeToClass($targetType); + + $targetObj = $this->fixtureFactory->get($targetClass, $targetId); + if(!$targetObj) $targetObj = $this->fixtureFactory->get($targetClass, $targetId); + + $fields = array('LinkToID' => $targetObj->ID); + $obj = $this->fixtureFactory->get($class, $id); + if($obj) { + $obj->update($fields); + } else { + $obj = $this->fixtureFactory->createObject($class, $id, $fields); + } + $obj->write(); + $obj->publish('Stage', 'Live'); + } + + /** + * Converts a natural language class description to an actual class name. + * Respects {@link DataObject::$singular_name} variations. + * Example: "redirector page" -> "RedirectorPage" + * + * @param String + * @return String Class name + */ + protected function convertTypeToClass($type) { + // Try direct mapping + $class = str_replace(' ', '', ucfirst($type)); + if(class_exists($class) || !is_subclass_of($class, 'DataObject')) { + return $class; + } + + // Fall back to singular names + foreach(array_values(\ClassInfo::subclassesFor('DataObject')) as $candidate) { + if(singleton($candidate)->singular_name() == $type) return $candidate; + } + + throw new \InvalidArgumentException(sprintf( + 'Class "%s" does not exist, or is not a subclass of DataObjet', + $class + )); + } + + +} From 47d7a19a23254bf5b93717734b8f5aea64202161 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Wed, 5 Jun 2013 13:30:15 +0200 Subject: [PATCH 2/4] Behat: Replace @database-defaults with explicit fixtures --- tests/behat/features/create-a-page.feature | 1 - tests/behat/features/edit-a-page.feature | 2 +- tests/behat/features/preview-a-page.feature | 4 +++- tests/behat/features/search-for-a-page.feature | 5 ++++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/behat/features/create-a-page.feature b/tests/behat/features/create-a-page.feature index a1df9adc..5baa46fe 100644 --- a/tests/behat/features/create-a-page.feature +++ b/tests/behat/features/create-a-page.feature @@ -1,4 +1,3 @@ -@database-defaults Feature: Create a page As an author I want to create a page in the CMS diff --git a/tests/behat/features/edit-a-page.feature b/tests/behat/features/edit-a-page.feature index cf7684f2..abf36e5e 100644 --- a/tests/behat/features/edit-a-page.feature +++ b/tests/behat/features/edit-a-page.feature @@ -1,10 +1,10 @@ -@database-defaults Feature: Edit a page As an author I want to edit a page in the CMS So that I correct errors and provide new information Background: + Given a page "About Us" Given I am logged in with "ADMIN" permissions And I go to "/admin/pages" Then I should see "About Us" in CMS Tree diff --git a/tests/behat/features/preview-a-page.feature b/tests/behat/features/preview-a-page.feature index 9f2d75c6..4d4013ba 100644 --- a/tests/behat/features/preview-a-page.feature +++ b/tests/behat/features/preview-a-page.feature @@ -1,9 +1,11 @@ -@database-defaults Feature: Preview a page As an author I want to preview the page I'm editing in the CMS So that I can see how it would look like to my visitors + Background: + Given a page "About Us" + @javascript Scenario: I can show a preview of the current page from the pages section Given I am logged in with "ADMIN" permissions diff --git a/tests/behat/features/search-for-a-page.feature b/tests/behat/features/search-for-a-page.feature index 23e51931..267dbacb 100644 --- a/tests/behat/features/search-for-a-page.feature +++ b/tests/behat/features/search-for-a-page.feature @@ -1,9 +1,12 @@ -@database-defaults Feature: Search for a page As an author I want to search for a page in the CMS So that I can efficiently navigate nested content structures + Background: + Given a page "About Us" + And a page "Contact Us" + @javascript Scenario: I can search for a page by its title Given I am logged in with "ADMIN" permissions From 8bd1e4373d1279d2a53adede13a6a4ceb286b54b Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Wed, 5 Jun 2013 13:37:19 +0200 Subject: [PATCH 3/4] Behat: Fixed spelling in test --- tests/behat/features/edit-a-page.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/behat/features/edit-a-page.feature b/tests/behat/features/edit-a-page.feature index abf36e5e..c29474f4 100644 --- a/tests/behat/features/edit-a-page.feature +++ b/tests/behat/features/edit-a-page.feature @@ -21,7 +21,7 @@ Feature: Edit a page When I fill in "Title" with "About Us!" And I fill in the "Content" HTML field with "my new content" - And I press the "Save Draft" button + And I press the "Save draft" button Then I should see a "Saved." notice When I follow "About Us" From d2105ef7a6357fe915bcb1d9b84928ef29ffebdc Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Wed, 5 Jun 2013 14:18:07 +0200 Subject: [PATCH 4/4] More verbose fixture step definitions Too many clashes with other steps otherwise, e.g. with 'And the preview contains "You can fill"'. Also removed some duplicated code no longer necessary because we use inheritance rather than composition --- .../Cms/Test/Behaviour/FixtureContext.php | 64 +------------------ tests/behat/features/edit-a-page.feature | 2 +- tests/behat/features/preview-a-page.feature | 4 +- .../behat/features/search-for-a-page.feature | 4 +- 4 files changed, 7 insertions(+), 67 deletions(-) diff --git a/tests/behat/features/bootstrap/SilverStripe/Cms/Test/Behaviour/FixtureContext.php b/tests/behat/features/bootstrap/SilverStripe/Cms/Test/Behaviour/FixtureContext.php index 58572fb1..a2c20914 100644 --- a/tests/behat/features/bootstrap/SilverStripe/Cms/Test/Behaviour/FixtureContext.php +++ b/tests/behat/features/bootstrap/SilverStripe/Cms/Test/Behaviour/FixtureContext.php @@ -21,45 +21,12 @@ require_once 'PHPUnit/Framework/Assert/Functions.php'; */ class FixtureContext extends \SilverStripe\BehatExtension\Context\FixtureContext { - protected $context; - - /** - * @var FixtureFactory - */ - protected $fixtureFactory; - - public function __construct(array $parameters) - { - $this->context = $parameters; - } - - public function getSession($name = null) - { - return $this->getMainContext()->getSession($name); - } - - /** - * @return \FixtureFactory - */ - public function getFixtureFactory() { - if(!$this->fixtureFactory) { - $this->fixtureFactory = \Injector::inst()->get('FixtureFactory', 'FixtureContextFactory'); - } - return $this->fixtureFactory; - } - - /** - * @param \FixtureFactory $factory - */ - public function setFixtureFactory(\FixtureFactory $factory) { - $this->fixtureFactory = $factory; - } /** * Find or create a redirector page and link to another existing page. - * Example: Given a page "My Redirect" which redirects to a page "Page 1" + * Example: Given a "page" "My Redirect" which redirects to a "page" "Page 1" * - * @Given /^(?:(an|a|the) )(?[^"]+)"(?[^"]+)" (:?which )?redirects to (?:(an|a|the) )(?[^"]+)"(?[^"]+)"$/ + * @Given /^(?:(an|a|the) )"(?[^"]+)" "(?[^"]+)" (:?which )?redirects to (?:(an|a|the) )"(?[^"]+)" "(?[^"]+)"$/ */ public function stepCreateRedirectorPage($type, $id, $targetType, $targetId) { @@ -80,31 +47,4 @@ class FixtureContext extends \SilverStripe\BehatExtension\Context\FixtureContext $obj->publish('Stage', 'Live'); } - /** - * Converts a natural language class description to an actual class name. - * Respects {@link DataObject::$singular_name} variations. - * Example: "redirector page" -> "RedirectorPage" - * - * @param String - * @return String Class name - */ - protected function convertTypeToClass($type) { - // Try direct mapping - $class = str_replace(' ', '', ucfirst($type)); - if(class_exists($class) || !is_subclass_of($class, 'DataObject')) { - return $class; - } - - // Fall back to singular names - foreach(array_values(\ClassInfo::subclassesFor('DataObject')) as $candidate) { - if(singleton($candidate)->singular_name() == $type) return $candidate; - } - - throw new \InvalidArgumentException(sprintf( - 'Class "%s" does not exist, or is not a subclass of DataObjet', - $class - )); - } - - } diff --git a/tests/behat/features/edit-a-page.feature b/tests/behat/features/edit-a-page.feature index c29474f4..8fd20bf0 100644 --- a/tests/behat/features/edit-a-page.feature +++ b/tests/behat/features/edit-a-page.feature @@ -4,7 +4,7 @@ Feature: Edit a page So that I correct errors and provide new information Background: - Given a page "About Us" + Given a "page" "About Us" Given I am logged in with "ADMIN" permissions And I go to "/admin/pages" Then I should see "About Us" in CMS Tree diff --git a/tests/behat/features/preview-a-page.feature b/tests/behat/features/preview-a-page.feature index 4d4013ba..6038b84f 100644 --- a/tests/behat/features/preview-a-page.feature +++ b/tests/behat/features/preview-a-page.feature @@ -4,7 +4,7 @@ Feature: Preview a page So that I can see how it would look like to my visitors Background: - Given a page "About Us" + Given a "page" "About Us" @javascript Scenario: I can show a preview of the current page from the pages section @@ -28,7 +28,7 @@ Feature: Preview a page When I follow "About Us" And I fill in the "Content" HTML field with "my new content" - And I press the "Save Draft" button + And I press the "Save draft" button And I press the "Preview ยป" button When I follow "Published Site" diff --git a/tests/behat/features/search-for-a-page.feature b/tests/behat/features/search-for-a-page.feature index 267dbacb..46ad3fec 100644 --- a/tests/behat/features/search-for-a-page.feature +++ b/tests/behat/features/search-for-a-page.feature @@ -4,8 +4,8 @@ Feature: Search for a page So that I can efficiently navigate nested content structures Background: - Given a page "About Us" - And a page "Contact Us" + Given a "page" "About Us" + And a "page" "Contact Us" @javascript Scenario: I can search for a page by its title