Merge remote-tracking branch 'origin/3.0' into 3.1

Conflicts:
	tests/behat/features/bootstrap/SilverStripe/Framework/Test/Behaviour/CmsUiContext.php
This commit is contained in:
Ingo Schommer 2013-06-05 14:37:54 +02:00
commit 7791f20f49
7 changed files with 120 additions and 95 deletions

View File

@ -0,0 +1,23 @@
<?php
/**
* @package framework
* @subpackage testing
*/
class BehatFixtureFactory extends \FixtureFactory {
public function createObject($name, $identifier, $data = null) {
if(!$data) $data = array();
// Copy identifier to some visible property unless its already defined.
// Exclude files, since they generate their own named based on the file path.
if(!is_a($name, 'File', true)) {
foreach(array('Name', 'Title') as $fieldName) {
if(singleton($name)->hasField($fieldName) && !isset($data[$fieldName])) {
$data[$fieldName] = $identifier;
break;
}
}
}
return parent::createObject($name, $identifier, $data);
}
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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<field>(?:[^"]|\\")*)" dropdown with "(?P<value>(?:[^"]|\\")*)"$/
* @When /^(?:|I )fill in "(?P<value>(?:[^"]|\\")*)" for the "(?P<field>(?:[^"]|\\")*)" 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();
}
/**

View File

@ -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,"
Then I should see "png,"

View File

@ -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

View File

@ -1,4 +1,3 @@
@database-defaults
Feature: My Profile
As a CMS user
I want to be able to change personal settings