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); $this->setValue($obj, $fieldName, $fieldVal, $fixtures);
} }
$obj->write(); $obj->write();
// Save to fixture before relationship processing in case of reflexive relationships // 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, use SilverStripe\BehatExtension\Context\SilverStripeContext,
SilverStripe\BehatExtension\Context\BasicContext, SilverStripe\BehatExtension\Context\BasicContext,
SilverStripe\BehatExtension\Context\LoginContext, SilverStripe\BehatExtension\Context\LoginContext,
SilverStripe\BehatExtension\Context\FixtureContext,
SilverStripe\Framework\Test\Behaviour\CmsFormsContext, SilverStripe\Framework\Test\Behaviour\CmsFormsContext,
SilverStripe\Framework\Test\Behaviour\CmsUiContext; SilverStripe\Framework\Test\Behaviour\CmsUiContext;
@ -20,6 +21,12 @@ require_once 'PHPUnit/Framework/Assert/Functions.php';
*/ */
class FeatureContext extends SilverStripeContext class FeatureContext extends SilverStripeContext
{ {
/**
* @var FixtureFactory
*/
protected $fixtureFactory;
/** /**
* Initializes context. * Initializes context.
* Every scenario gets it's own context object. * Every scenario gets it's own context object.
@ -28,11 +35,46 @@ class FeatureContext extends SilverStripeContext
*/ */
public function __construct(array $parameters) public function __construct(array $parameters)
{ {
parent::__construct($parameters);
$this->useContext('BasicContext', new BasicContext($parameters)); $this->useContext('BasicContext', new BasicContext($parameters));
$this->useContext('LoginContext', new LoginContext($parameters)); $this->useContext('LoginContext', new LoginContext($parameters));
$this->useContext('CmsFormsContext', new CmsFormsContext($parameters)); $this->useContext('CmsFormsContext', new CmsFormsContext($parameters));
$this->useContext('CmsUiContext', new CmsUiContext($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\BehatContext,
Behat\Behat\Context\Step, Behat\Behat\Context\Step,
Behat\Behat\Exception\PendingException, Behat\Behat\Exception\PendingException,
Behat\Mink\Exception\ElementNotFoundException; Behat\Mink\Exception\ElementNotFoundException,
use Behat\Gherkin\Node\PyStringNode, Behat\Gherkin\Node\PyStringNode,
Behat\Gherkin\Node\TableNode; 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 the "(?P<field>(?:[^"]|\\")*)" dropdown with "(?P<value>(?:[^"]|\\")*)"$/
* @When /^(?:|I )fill in "(?P<value>(?:[^"]|\\")*)" for the "(?P<field>(?:[^"]|\\")*)" dropdown$/ * @When /^(?:|I )fill in "(?P<value>(?:[^"]|\\")*)" for the "(?P<field>(?:[^"]|\\")*)" dropdown$/
@ -320,6 +320,12 @@ class CmsUiContext extends BehatContext
$field = $this->fixStepArgument($field); $field = $this->fixStepArgument($field);
$value = $this->fixStepArgument($value); $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. // Given the fuzzy matching, we might get more than one matching field.
$formFields = array(); $formFields = array();
@ -338,26 +344,28 @@ class CmsUiContext extends BehatContext
); );
} }
assertGreaterThan(0, count($formFields), sprintf( // Find by name (incl. hidden fields)
'Chosen.js dropdown named "%s" not found', if(!$formFields) {
$field $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(); $containers = array();
foreach($formFields as $formField) { foreach($formFields as $formField) {
// Traverse up to field holder
$containerCandidate = $formField;
do { do {
$containerCandidate = $containerCandidate->getParent(); $container = $formField->getParent();
} while($containerCandidate && !preg_match('/field/', $containerCandidate->getAttribute('class'))); $containerClasses = explode(' ', $container->getAttribute('class'));
$containers[] = $container;
if( } while(
$containerCandidate $container
&& $containerCandidate->isVisible() && in_array('field', $containerClasses)
&& preg_match('/field/', $containerCandidate->getAttribute('class')) && $container->getTagName() != 'form'
) { );
$containers[] = $containerCandidate;
}
} }
assertGreaterThan(0, count($containers), 'Chosen.js field container not found'); assertGreaterThan(0, count($containers), 'Chosen.js field container not found');
@ -371,17 +379,27 @@ class CmsUiContext extends BehatContext
$this->getSession()->wait(100); // wait for dropdown overlay to appear $this->getSession()->wait(100); // wait for dropdown overlay to appear
$linkEl->click(); $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)); $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', 'Chosen.js list element with title "%s" not found',
$value $value
)); ));
}
// Dropdown flyout might be animated $listEl->find('xpath', './/a')->click();
// $this->getSession()->wait(1000, 'jQuery(":animated").length == 0');
$this->getSession()->wait(300);
$listEl->click();
} }
/** /**

View File

@ -5,37 +5,10 @@ Feature: Manage files
So that I can insert them into my content efficiently So that I can insert them into my content efficiently
Background: Background:
# Idea: We could weave the database reset into this through Given a "file" "assets/folder1/file1.jpg"
# saying 'Given there are ONLY the following...'. And a "file" "assets/folder1/folder1.1/file2.jpg"
Given there are the following Folder records And a "folder" "assets/folder2"
"""
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
"""
And I am logged in with "ADMIN" permissions 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" And I go to "/admin/assets"
@modal @modal
@ -76,7 +49,7 @@ Feature: Manage files
Scenario: I can change the folder of a file Scenario: I can change the folder of a file
Given I click on "folder1" in the "Files" table Given I click on "folder1" in the "Files" table
And I click on "file1" in the "folder1" 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 And I press the "Save" button
# /show/0 is to ensure that we are on top level folder # /show/0 is to ensure that we are on top level folder
And I go to "/admin/assets/show/0" And I go to "/admin/assets/show/0"

View File

@ -1,48 +1,21 @@
@database-defaults @javascript
Feature: Manage users Feature: Manage users
As a site administrator As a site administrator
I want to create and manage user accounts on my site I want to create and manage user accounts on my site
So that I can control access to the CMS So that I can control access to the CMS
Background: Background:
Given there are the following Permission records 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"
admin: And the "group" "Admin Group" has permissions "Full administrative rights"
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
"""
And I am logged in with "ADMIN" permissions And I am logged in with "ADMIN" permissions
And I go to "/admin/security" And I go to "/admin/security"
@javascript
Scenario: I can list all users regardless of group Scenario: I can list all users regardless of group
When I click the "Users" CMS tab When I click the "Users" CMS tab
Then I should see "admin@test.com" in the "#Root_Users" element Then I should see "admin@test.com" in the "#Root_Users" element
And I should see "staffmember@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 Scenario: I can list all users in a specific group
When I click the "Groups" CMS tab When I click the "Groups" CMS tab
# TODO Please check how performant this is # 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 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 And I should not see "staffmember@test.com" in the "#Root_Members" element
@javascript
Scenario: I can add a user to the system Scenario: I can add a user to the system
When I click the "Users" CMS tab When I click the "Users" CMS tab
And I press the "Add Member" button And I press the "Add Member" button
@ -64,12 +36,10 @@ Feature: Manage users
When I go to "admin/security/" When I go to "admin/security/"
Then I should see "john.doe@test.com" in the "#Root_Users" element 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 Scenario: I can edit an existing user and add him to an existing group
When I click the "Users" CMS tab When I click the "Users" CMS tab
And I click "staffmember@test.com" in the "#Root_Users" element And I click "staffmember@test.com" in the "#Root_Users" element
And I select "Admin Group" from "Groups" And I select "Admin Group" from "Groups"
And I additionally select "Administrators" from "Groups"
And I press the "Save" button And I press the "Save" button
Then I should see a "Saved Member" message 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 And I click "Admin Group" in the "#Root_Groups" element
Then I should see "staffmember@test.com" Then I should see "staffmember@test.com"
@javascript
Scenario: I can delete an existing user Scenario: I can delete an existing user
When I click the "Users" CMS tab When I click the "Users" CMS tab
And I click "staffmember@test.com" in the "#Root_Users" element And I click "staffmember@test.com" in the "#Root_Users" element

View File

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