diff --git a/dev/BehatFixtureFactory.php b/dev/BehatFixtureFactory.php new file mode 100644 index 000000000..b4ce190de --- /dev/null +++ b/dev/BehatFixtureFactory.php @@ -0,0 +1,23 @@ +hasField($fieldName) && !isset($data[$fieldName])) { + $data[$fieldName] = $identifier; + break; + } + } + } + + return parent::createObject($name, $identifier, $data); + } +} \ No newline at end of file diff --git a/dev/FixtureBlueprint.php b/dev/FixtureBlueprint.php index 101e28b8b..e74bdee11 100644 --- a/dev/FixtureBlueprint.php +++ b/dev/FixtureBlueprint.php @@ -116,6 +116,7 @@ class FixtureBlueprint { $this->setValue($obj, $fieldName, $fieldVal, $fixtures); } + $obj->write(); // Save to fixture before relationship processing in case of reflexive relationships diff --git a/tests/behat/features/bootstrap/FeatureContext.php b/tests/behat/features/bootstrap/FeatureContext.php index a522e8a7c..a9c4835d4 100644 --- a/tests/behat/features/bootstrap/FeatureContext.php +++ b/tests/behat/features/bootstrap/FeatureContext.php @@ -5,6 +5,7 @@ namespace SilverStripe\Framework\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; @@ -20,6 +21,12 @@ require_once 'PHPUnit/Framework/Assert/Functions.php'; */ class FeatureContext extends SilverStripeContext { + + /** + * @var FixtureFactory + */ + protected $fixtureFactory; + /** * Initializes context. * Every scenario gets it's own context object. @@ -28,11 +35,46 @@ class FeatureContext extends SilverStripeContext */ public function __construct(array $parameters) { + parent::__construct($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); + $fixtureContext = new FixtureContext($parameters); + $fixtureContext->setFixtureFactory($this->getFixtureFactory()); + $this->useContext('FixtureContext', $fixtureContext); + + // Use blueprints to set user name from identifier + $factory = $fixtureContext->getFixtureFactory(); + $blueprint = \Injector::inst()->create('FixtureBlueprint', 'Member'); + $blueprint->addCallback('beforeCreate', function($identifier, &$data, &$fixtures) { + if(!isset($data['FirstName'])) $data['FirstName'] = $identifier; + }); + $factory->define('Member', $blueprint); + } + + public function setMinkParameters(array $parameters) + { + parent::setMinkParameters($parameters); + + if(isset($parameters['files_path'])) { + $this->getSubcontext('FixtureContext')->setFilesPath($parameters['files_path']); + } + } + + /** + * @return FixtureFactory + */ + public function getFixtureFactory() { + if(!$this->fixtureFactory) { + $this->fixtureFactory = \Injector::inst()->create('BehatFixtureFactory'); + } + return $this->fixtureFactory; + } + + public function setFixtureFactory(FixtureFactory $factory) { + $this->fixtureFactory = $factory; } } diff --git a/tests/behat/features/bootstrap/SilverStripe/Framework/Test/Behaviour/CmsUiContext.php b/tests/behat/features/bootstrap/SilverStripe/Framework/Test/Behaviour/CmsUiContext.php index f7d191830..fe5dea693 100644 --- a/tests/behat/features/bootstrap/SilverStripe/Framework/Test/Behaviour/CmsUiContext.php +++ b/tests/behat/features/bootstrap/SilverStripe/Framework/Test/Behaviour/CmsUiContext.php @@ -7,8 +7,8 @@ use Behat\Behat\Context\ClosuredContextInterface, Behat\Behat\Context\BehatContext, Behat\Behat\Context\Step, Behat\Behat\Exception\PendingException, - Behat\Mink\Exception\ElementNotFoundException; -use Behat\Gherkin\Node\PyStringNode, + Behat\Mink\Exception\ElementNotFoundException, + Behat\Gherkin\Node\PyStringNode, Behat\Gherkin\Node\TableNode; @@ -310,7 +310,7 @@ class CmsUiContext extends BehatContext } /** - * Workaround for chosen.js dropdowns which hide the original dropdown field. + * Workaround for chosen.js dropdowns or tree dropdowns which hide the original dropdown field. * * @When /^(?:|I )fill in the "(?P(?:[^"]|\\")*)" dropdown with "(?P(?:[^"]|\\")*)"$/ * @When /^(?:|I )fill in "(?P(?:[^"]|\\")*)" for the "(?P(?:[^"]|\\")*)" dropdown$/ @@ -320,6 +320,12 @@ class CmsUiContext extends BehatContext $field = $this->fixStepArgument($field); $value = $this->fixStepArgument($value); + $nativeField = $this->getSession()->getPage()->findField($field); + if($nativeField) { + $nativeField->selectOption($value); + return; + } + // Given the fuzzy matching, we might get more than one matching field. $formFields = array(); @@ -338,30 +344,32 @@ class CmsUiContext extends BehatContext ); } - assertGreaterThan(0, count($formFields), sprintf( - 'Chosen.js dropdown named "%s" not found', - $field - )); + // Find by name (incl. hidden fields) + if(!$formFields) { + $formFields = $this->getSession()->getPage()->findAll('xpath', "//*[@name='$field']"); + } + assertGreaterThan(0, count($formFields), sprintf( + 'Chosen.js dropdown named "%s" not found', + $field + )); + + // Traverse up to field holder $containers = array(); foreach($formFields as $formField) { - // Traverse up to field holder - $containerCandidate = $formField; do { - $containerCandidate = $containerCandidate->getParent(); - } while($containerCandidate && !preg_match('/field/', $containerCandidate->getAttribute('class'))); - - if( - $containerCandidate - && $containerCandidate->isVisible() - && preg_match('/field/', $containerCandidate->getAttribute('class')) - ) { - $containers[] = $containerCandidate; - } + $container = $formField->getParent(); + $containerClasses = explode(' ', $container->getAttribute('class')); + $containers[] = $container; + } while( + $container + && in_array('field', $containerClasses) + && $container->getTagName() != 'form' + ); } assertGreaterThan(0, count($containers), 'Chosen.js field container not found'); - + // Default to first visible container $container = $containers[0]; @@ -371,17 +379,27 @@ class CmsUiContext extends BehatContext $this->getSession()->wait(100); // wait for dropdown overlay to appear $linkEl->click(); + if(in_array('treedropdown', $containerClasses)) { + // wait for ajax dropdown to load + $this->getSession()->wait( + 5000, + "jQuery('#" . $container->getAttribute('id') . " .treedropdownfield-panel li').length > 0" + ); + } else { + // wait for dropdown overlay to appear (might be animated) + $this->getSession()->wait(300); + } + + $listEl = $container->find('xpath', sprintf('.//li[contains(normalize-space(string(.)), \'%s\')]', $value)); - assertNotNull($listEl, sprintf( + if(null === $listEl) { + throw new \InvalidArgumentException(sprintf( 'Chosen.js list element with title "%s" not found', $value )); + } - // Dropdown flyout might be animated - // $this->getSession()->wait(1000, 'jQuery(":animated").length == 0'); - $this->getSession()->wait(300); - - $listEl->click(); + $listEl->find('xpath', './/a')->click(); } /** diff --git a/tests/behat/features/manage-files.feature b/tests/behat/features/manage-files.feature index 23996cebd..f4c39fad8 100644 --- a/tests/behat/features/manage-files.feature +++ b/tests/behat/features/manage-files.feature @@ -5,37 +5,10 @@ Feature: Manage files So that I can insert them into my content efficiently Background: - # Idea: We could weave the database reset into this through - # saying 'Given there are ONLY the following...'. - Given there are the following Folder records - """ - folder1: - Filename: assets/folder1 - folder1.1: - Filename: assets/folder1/folder1.1 - Parent: =>Folder.folder1 - folder2: - Filename: assets/folder2 - Name: folder2 - """ - And there are the following File records - """ - file1: - Filename: assets/folder1/file1.jpg - Name: file1.jpg - Parent: =>Folder.folder1 - file2: - Filename: assets/folder1/folder1.1/file2.jpg - Name: file2.jpg - Parent: =>Folder.folder1.1 - """ + Given a "file" "assets/folder1/file1.jpg" + And a "file" "assets/folder1/folder1.1/file2.jpg" + And a "folder" "assets/folder2" And I am logged in with "ADMIN" permissions - # Alternative fixture shortcuts, with their titles - # as shown in admin/security rather than technical permission codes. - # Just an idea for now, could be handled by YAML fixtures as well -# And I am logged in with the following permissions -# - Access to 'Pages' section -# - Access to 'Files' section And I go to "/admin/assets" @modal @@ -76,7 +49,7 @@ Feature: Manage files Scenario: I can change the folder of a file Given I click on "folder1" in the "Files" table And I click on "file1" in the "folder1" table - And I fill in =>Folder.folder2 for "ParentID" + And I fill in "folder2" for "ParentID" dropdown And I press the "Save" button # /show/0 is to ensure that we are on top level folder And I go to "/admin/assets/show/0" @@ -86,4 +59,4 @@ Feature: Manage files Scenario: I can see allowed extensions help When I go to "/admin/assets/add" And I follow "Show allowed extensions" - Then I should see "png," \ No newline at end of file + Then I should see "png," diff --git a/tests/behat/features/manage-users.feature b/tests/behat/features/manage-users.feature index 117e6bc14..7b4a7e2d7 100644 --- a/tests/behat/features/manage-users.feature +++ b/tests/behat/features/manage-users.feature @@ -1,48 +1,21 @@ -@database-defaults +@javascript Feature: Manage users As a site administrator I want to create and manage user accounts on my site So that I can control access to the CMS Background: - Given there are the following Permission records - """ - admin: - Code: ADMIN - security-admin: - Code: CMS_ACCESS_SecurityAdmin - """ - And there are the following Group records - """ - admingroup: - Title: Admin Group - Code: admin - Permissions: =>Permission.admin - staffgroup: - Title: Staff Group - Code: staffgroup - """ - And there are the following Member records - """ - admin: - FirstName: Admin - Email: admin@test.com - Groups: =>Group.admingroup - staffmember: - FirstName: Staff - Email: staffmember@test.com - Groups: =>Group.staffgroup - """ + Given a "member" "Admin" belonging to "Admin Group" with "Email"="admin@test.com" + And a "member" "Staff" belonging to "Staff Group" with "Email"="staffmember@test.com" + And the "group" "Admin Group" has permissions "Full administrative rights" And I am logged in with "ADMIN" permissions And I go to "/admin/security" - @javascript Scenario: I can list all users regardless of group When I click the "Users" CMS tab Then I should see "admin@test.com" in the "#Root_Users" element And I should see "staffmember@test.com" in the "#Root_Users" element - @javascript Scenario: I can list all users in a specific group When I click the "Groups" CMS tab # TODO Please check how performant this is @@ -50,7 +23,6 @@ Feature: Manage users Then I should see "admin@test.com" in the "#Root_Members" element And I should not see "staffmember@test.com" in the "#Root_Members" element - @javascript Scenario: I can add a user to the system When I click the "Users" CMS tab And I press the "Add Member" button @@ -64,12 +36,10 @@ Feature: Manage users When I go to "admin/security/" Then I should see "john.doe@test.com" in the "#Root_Users" element - @javascript Scenario: I can edit an existing user and add him to an existing group When I click the "Users" CMS tab And I click "staffmember@test.com" in the "#Root_Users" element And I select "Admin Group" from "Groups" - And I additionally select "Administrators" from "Groups" And I press the "Save" button Then I should see a "Saved Member" message @@ -78,7 +48,6 @@ Feature: Manage users And I click "Admin Group" in the "#Root_Groups" element Then I should see "staffmember@test.com" - @javascript Scenario: I can delete an existing user When I click the "Users" CMS tab And I click "staffmember@test.com" in the "#Root_Users" element diff --git a/tests/behat/features/profile.feature b/tests/behat/features/profile.feature index 3ca0e3ab9..3ae1f61ee 100644 --- a/tests/behat/features/profile.feature +++ b/tests/behat/features/profile.feature @@ -1,4 +1,3 @@ -@database-defaults Feature: My Profile As a CMS user I want to be able to change personal settings