diff --git a/README.md b/README.md index e01941d..6c4746f 100644 --- a/README.md +++ b/README.md @@ -1,255 +1,9 @@ SilverStripe-Behaviour-Testing-Framework ======================================== -## Getting started +Project migrated into SilverStripe repositories. -As well as this package, you will need to download/install: +https://github.com/silverstripe/sapphire/pull/948 +https://github.com/silverstripe/silverstripe-cms/pull/236 +https://github.com/silverstripe/silverstripe-installer/pull/24 -* [composer](http://packagist.org/) -* [PHPUnit](https://github.com/sebastianbergmann/phpunit/) -* [Selenium](http://seleniumhq.org/) - -Composer dependencies file is included in this repository, so all you need to do for now -on either Linux or Mac OS X is: - - # Execute the following in your project root - # (or where composer.json is located) - # This will install composer for you - curl -s http://getcomposer.org/installer | php - # This will install dependencies required - php composer.phar install - -To install PHPUnit: - - # This will install PHPUnit - pear channel-discover pear.phpunit.de - pear install phpunit/PHPUnit - -To install Selenium: - - # This will download selenium - wget http://selenium.googlecode.com/files/selenium-server-standalone-2.25.0.jar - - -### Additional requirements - -Because this testing framework is intended to be used with SilverStripe, you have to -download and install it too. The minimum version required is `3.0`. Recommended way -to get started is to [install from source](http://doc.silverstripe.org/framework/en/installation/from-source), -but it's really up to your preference. - -No database content is required because it will be created automatically when needed. - -## Configuration - -`admin_url` and `login_url` should not be changed unless you customized them somehow. - -Optional `screenshot_path` variable is used to store screenshot of a last known state -of a failed step. It defaults to whatever is returned by PHP's `sys_get_temp_dir()`. -Screenshot names within that directory consist of feature file filename and line -number that failed. - - # behat.yml - default: - # ... - context: - parameters: - admin_url: /admin/ - login_url: /Security/login - screenshot_path: features/screenshots/ - -### Configuring extensions - -#### MinkExtension - -You will probably need to change the base URL that is used during the test process. -It is used every time you use relative URLs in your feature descriptions. -It will also be used by [file to URL mapping](http://doc.silverstripe.org/framework/en/topics/commandline#configuration) in `SilverStripeExtension`. - -You also have to change `files_path` path when you want to support file uploads. -Otherwise, you can remove it from the config. Currently only absolute paths are supported. - -Only selenium2 sessions are supported at the moment, but `default_session` is the place -to change it if you want to try other driver sessions like `goutte`. - - # behat.yml - default: - # ... - extensions: - Behat\MinkExtension\Extension: - base_url: http://localhost - files_path: /absolute/path/to/files/ - default_session: selenium2 - selenium2: ~ - -#### SilverStripeExtension - -You also can change the path to the SilverStripe framework with `framework_path`. -It supports both absolute and relative (to `behat.yml` file) paths. - -Because SilverStripe uses AJAX requests quite extensively, we had to invent a way -to deal with them more efficiently and less verbose than just -Optional `ajax_steps` is used to match steps defined there so they can be "caught" by -[special AJAX handlers](http://blog.scur.pl/2012/06/ajax-callback-support-behat-mink/) that tweak the delays. -You can either use a pipe delimited string or a list of substrings that match step definition. - - # behat.yml - default: - # ... - extensions: - Behat\SilverStripeExtension\Extension: - framework_path: ../../ - # ajax_steps: "go to|follow|press|click|submit" - ajax_steps: - - go to - - follow - - press - - click - - submit - -### Additional profiles - -By default, `MinkExtension` is using `FirefoxDriver`. -Let's say you want to user `ChromeDriver` too. - -You can either override the `selenium2` setting in default profile or add another -profile that can be run using `bin/behat --profile=PROFILE_NAME`, where `PROFILE_NAME` -could be `chrome`. - - chrome: - extensions: - Behat\MinkExtension\Extension: - selenium2: - capabilities: - browserName: chrome - version: ANY - -## Running tests - -### Starting the selenium server - -You can either run the server in a separate Terminal tab: - - java -jar selenium-server-standalone-2.25.0.jar - -Or you can run it in the background: - - java -jar selenium-server-standalone-2.25.0.jar > /dev/null & - - -### Running the tests - -You will have Behat binary located in `bin` directory in your project root (or where `composer.json` is located). - -By default, Behat will use Selenium2 driver. -Selenium will also try to use chrome browser. Refer to `behat.yml` for details. - - # This will run all feature tests located in `features` directory - bin/behat - - # This will run all feature tests using chrome profile - bin/behat --profile=chrome - -## FAQ - -### Why does the module need to know about the framework path on the filesystem? - -Sometimes SilverStripe needs to know the URL of your site. When you're visiting -your site in a web browser this is easy to work out, but if you're executing -scripts on the command-line, it has no way of knowing. - -To work this out, this module is using [file to URL mapping](http://doc.silverstripe.org/framework/en/topics/commandline#configuration). - -### How does the module interact with the SS database? - -The module creates temporary database on init and is switching to the alternative -database session before every scenario by using `/dev/tests/setdb` TestRunner -endpoint. - -It also populates this temporary database with the default records if necessary. - -It is possible to include your own fixtures, it is explained further. - -### How do I define fixtures? - -Fixtures should be provided in YAML format (standard SilverStripe fixture format) -as [PyStrings](http://docs.behat.org/guides/1.gherkin.html#pystrings) - -Take a look at the sample fixture logic first: - - Given there are the following Permission records - """ - admin: - Code: ADMIN - """ - And there are the following Group records - """ - admingroup: - Title: Admin Group - Code: admin - Permissions: =>Permission.admin - """ - And there are the following Member records - """ - admin: - FirstName: Admin - Email: admin@test.com - Groups: =>Group.admingroup - """ - -In this example, the fixture is used to create Admin member with admin permissions. - -As you can see, there are special Gherkin steps that take care of loading -fixtures into database. They use the following format: - - Given there are the following TableName records - """ - RowIdentifier: - ColumnName: Value - """ - -Fixtures may also use a `=>` symbol to indicate relationships between records. -In the example above `=>Permission.admin` will be replaced with row `ID` of a -`Permission` record that has `RowIdentifier` set as `admin`. - -### When do fixtures get created? - -Fixtures are created where you defined them. If you want the fixtures to be created -before every scenario, define them in [Background](http://docs.behat.org/guides/1.gherkin.html#backgrounds). - -If you want them to be created only when a particular scenario runs, define them there. - -### When do fixtures get cleared during the feature runs? - -Fixtures are usually not cleared between scenarios. You can alter this behaviour -by tagging the feature or scenario with `@database-defaults` tag. - -The module runner empties the database before each scenario tagged with -`@database-defaults` and populates it with default records (usually a set of -default pages). - -### How do I debug when something goes wrong? - -First, read the console output. Behat will tell you which steps have failed. - -SilverStripe Behaviour Testing Framework also notifies you about some events. -It tries to catch some JavaScript errors and AJAX errors as well although it -is limited to errors that occur after the page is loaded. - -Screenshot will be taken by the module every time the step is marked as failed. -Refer to configuration section above to know how to set up the screenshot path. - -If you are unable to debug using the information collected with the above -methods, it is possible to delay the step execution by adding the following step: - - And I wait for "10000" - -where `10000` is the number of millisecods you wish the session to wait. -It is very useful when you want to look at the error or developer console -inside the browser or if you want to interact with the session page manually. - -## Useful resources - -* [SilverStripe CMS architecture](http://doc.silverstripe.org/sapphire/en/trunk/reference/cms-architecture) -* [SilverStripe Framework Test Module](https://github.com/silverstripe-labs/silverstripe-frameworktest) -* [SilverStripe Unit and Integration Testing](http://doc.silverstripe.org/sapphire/en/trunk/topics/testing) diff --git a/_manifest_exclude b/_manifest_exclude deleted file mode 100644 index e69de29..0000000 diff --git a/behat.yml b/behat.yml deleted file mode 100644 index 7ceb7d1..0000000 --- a/behat.yml +++ /dev/null @@ -1,36 +0,0 @@ -# behat.yml -default: - context: - parameters: - admin_url: /admin/ - login_url: /Security/login - screenshot_path: %behat.paths.features%/screenshots/ - extensions: - Behat\SilverStripeExtension\Extension: - framework_path: ../../ - ajax_steps: - - go to - - follow - - press - - click - - submit - Behat\MinkExtension\Extension: - base_url: http://localhost - files_path: %behat.paths.features%/files/ - default_session: selenium2 - javascript_session: selenium2 - goutte: ~ - selenium2: -# browser: chrome - capabilities: - version: ANY - browserName: chrome -# host: 'http://localhost:4444/wd/hub' - -firefox: - extensions: - Behat\MinkExtension\Extension: - selenium2: - capabilities: - version: ANY - browserName: firefox diff --git a/composer.json b/composer.json deleted file mode 100644 index b3707cc..0000000 --- a/composer.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "require": { - "behat/behat": "2.4@stable", - "behat/mink": "1.4@stable", - "behat/mink-extension": "1.0@stable", - "behat/silverstripe-extension": "*", - "fabpot/goutte": "dev-master", - "behat/mink-goutte-driver": "*", - "behat/mink-selenium2-driver": "*", - "symfony/yaml": "*" - }, - "minimum-stability": "dev", - "config": { - "bin-dir": "bin" - } -} diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php deleted file mode 100644 index fdd54e5..0000000 --- a/features/bootstrap/FeatureContext.php +++ /dev/null @@ -1,39 +0,0 @@ -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); - } -} diff --git a/features/bootstrap/SilverStripe/Test/Behaviour/BasicContext.php b/features/bootstrap/SilverStripe/Test/Behaviour/BasicContext.php deleted file mode 100644 index b30ec38..0000000 --- a/features/bootstrap/SilverStripe/Test/Behaviour/BasicContext.php +++ /dev/null @@ -1,332 +0,0 @@ -context = $parameters; - } - - /** - * Get Mink session from MinkContext - */ - public function getSession($name = null) - { - return $this->getMainContext()->getSession($name); - } - - /** - * @AfterStep ~@modal - * - * Excluding scenarios with @modal tag is required, - * because modal dialogs stop any JS interaction - */ - public function appendErrorHandlerBeforeStep(StepEvent $event) - { - $javascript = <<getSession()->executeScript($javascript); - } - - /** - * @AfterStep ~@modal - * - * Excluding scenarios with @modal tag is required, - * because modal dialogs stop any JS interaction - */ - public function readErrorHandlerAfterStep(StepEvent $event) - { - $page = $this->getSession()->getPage(); - - $jserrors = $page->find('xpath', '//body[@data-jserrors]'); - if (null !== $jserrors) { - $this->takeScreenshot($event); - file_put_contents('php://stderr', $jserrors->getAttribute('data-jserrors') . PHP_EOL); - } - - $javascript = <<getSession()->executeScript($javascript); - } - - /** - * Hook into jQuery ajaxStart, ajaxSuccess and ajaxComplete events. - * Prepare __ajaxStatus() functions and attach them to these handlers. - * Event handlers are removed after one run. - * - * @BeforeStep - */ - public function handleAjaxBeforeStep(StepEvent $event) - { - $ajax_enabled_steps = $this->getMainContext()->getAjaxEnabledSteps(); - $ajax_enabled_steps = implode('|', array_filter($ajax_enabled_steps)); - - if (empty($ajax_enabled_steps) || !preg_match('/(' . $ajax_enabled_steps . ')/i', $event->getStep()->getText())) { - return; - } - - $javascript = <<getSession()->executeScript($javascript); - } - - /** - * Wait for the __ajaxStatus()to return anything but 'waiting'. - * Don't wait longer than 5 seconds. - * - * Don't unregister handler if we're dealing with modal windows - * - * @AfterStep ~@modal - */ - public function handleAjaxAfterStep(StepEvent $event) - { - $ajax_enabled_steps = $this->getMainContext()->getAjaxEnabledSteps(); - $ajax_enabled_steps = implode('|', array_filter($ajax_enabled_steps)); - - if (empty($ajax_enabled_steps) || !preg_match('/(' . $ajax_enabled_steps . ')/i', $event->getStep()->getText())) { - return; - } - - $this->handleAjaxTimeout(); - - $javascript = <<getSession()->executeScript($javascript); - } - - public function handleAjaxTimeout() - { - $this->getSession()->wait(5000, - "(typeof window.__ajaxStatus !== 'undefined' ? window.__ajaxStatus() : 'no ajax') !== 'waiting'" - ); - - // wait additional 100ms to allow DOM to update - $this->getSession()->wait(100); - } - - /** - * Take screenshot when step fails. - * Works only with Selenium2Driver. - * - * @AfterStep - */ - public function takeScreenshotAfterFailedStep(StepEvent $event) - { - if (4 === $event->getResult()) { - $this->takeScreenshot($event); - } - } - - public function takeScreenshot(StepEvent $event) { - $driver = $this->getSession()->getDriver(); - // quit silently when unsupported - if (!($driver instanceof Selenium2Driver)) { - return; - } - - $parent = $event->getLogicalParent(); - $feature = $parent->getFeature(); - $step = $event->getStep(); - $screenshot_path = null; - - if (isset($this->context['screenshot_path'])) { - $screenshot_path = realpath($this->context['screenshot_path']); - if (!$screenshot_path) { - \Filesystem::makeFolder($this->context['screenshot_path']); - $screenshot_path = realpath($this->context['screenshot_path']); - } - } - if (!$screenshot_path) { - $screenshot_path = realpath(sys_get_temp_dir()); - } - - if (!file_exists($screenshot_path)) { - file_put_contents('php://stderr', sprintf('"%s" is not valid directory and failed to create it' . PHP_EOL, $this->context['screenshot_path'])); - return; - } - - if (file_exists($screenshot_path) && !is_dir($screenshot_path)) { - file_put_contents('php://stderr', sprintf('"%s" is not valid directory' . PHP_EOL, $this->context['screenshot_path'])); - return; - } - if (file_exists($screenshot_path) && !is_writable($screenshot_path)) { - file_put_contents('php://stderr', sprintf('"%s" directory is not writable' . PHP_EOL, $screenshot_path)); - return; - } - - $screenshot_path = sprintf('%s/%s_%d.png', $screenshot_path, basename($feature->getFile()), $step->getLine()); - $screenshot = $driver->wdSession->screenshot(); - file_put_contents($screenshot_path, base64_decode($screenshot)); - file_put_contents('php://stderr', sprintf('Saving screenshot into %s' . PHP_EOL, $screenshot_path)); - } - - /** - * @Then /^I should be redirected to "([^"]+)"/ - */ - public function stepIShouldBeRedirectedTo($url) - { - if ($this->getMainContext()->canIntercept()) { - $client = $this->getSession()->getDriver()->getClient(); - $client->followRedirects(true); - $client->followRedirect(); - - $url = $this->getMainContext()->joinUrlParts($this->context['base_url'], $url); - - assertTrue($this->getMainContext()->isCurrentUrlSimilarTo($url), sprintf('Current URL is not %s', $url)); - } - } - - /** - * @Given /^I wait for "(\d+)"$/ - */ - public function stepIWaitFor($ms) - { - $this->getSession()->wait($ms); - } - - /** - * @Given /^I press "([^"]*)" button$/ - */ - public function stepIPressButton($button) - { - $page = $this->getSession()->getPage(); - - $button_element = $page->find('named', array('link_or_button', "'$button'")); - assertNotNull($button_element, sprintf('%s button not found', $button)); - - $button_element->click(); - } - - /** - * @Given /^I click "([^"]*)" in the "([^"]*)" element$/ - */ - public function iClickInTheElement($text, $selector) - { - $page = $this->getSession()->getPage(); - - $parent_element = $page->find('css', $selector); - assertNotNull($parent_element, sprintf('"%s" element not found', $selector)); - - $element = $parent_element->find('xpath', sprintf('//*[count(*)=0 and contains(.,"%s")]', $text)); - assertNotNull($element, sprintf('"%s" not found', $text)); - - $element->click(); - } - - /** - * @Given /^I type "([^"]*)" into the dialog$/ - */ - public function iTypeIntoTheDialog($data) - { - $data = array( - 'text' => $data, - ); - $this->getSession()->getDriver()->wdSession->postAlert_text($data); - } - - /** - * @Given /^I confirm the dialog$/ - */ - public function iConfirmTheDialog() - { - $this->getSession()->getDriver()->wdSession->accept_alert(); - $this->handleAjaxTimeout(); - } - - /** - * @Given /^I dismiss the dialog$/ - */ - public function iDismissTheDialog() - { - $this->getSession()->getDriver()->wdSession->dismiss_alert(); - $this->handleAjaxTimeout(); - } - - /** - * @Given /^(I attach the file .*) with HTML5$/ - */ - public function iAttachTheFileTo($step) - { - $this->getSession()->evaluateScript("jQuery('.ss-uploadfield-editandorganize').show()"); - $this->getSession()->evaluateScript("jQuery('[name=\"AssetUploadField\"]').css({opacity:1,visibility:'visible',height:'1px',width:'1px'})"); - $this->getSession()->evaluateScript("jQuery('[name=\"files[]\"]').css({opacity:1,visibility:'visible',height:'1px',width:'1px'})"); - $this->getSession()->wait(1000); - - return new Step\Given($step); - } -} diff --git a/features/bootstrap/SilverStripe/Test/Behaviour/CmsFormsContext.php b/features/bootstrap/SilverStripe/Test/Behaviour/CmsFormsContext.php deleted file mode 100644 index bffcdfc..0000000 --- a/features/bootstrap/SilverStripe/Test/Behaviour/CmsFormsContext.php +++ /dev/null @@ -1,72 +0,0 @@ -context = $parameters; - } - - /** - * Get Mink session from MinkContext - */ - public function getSession($name = null) - { - return $this->getMainContext()->getSession($name); - } - - /** - * @Then /^I should see an edit page form$/ - */ - public function stepIShouldSeeAnEditPageForm() - { - $page = $this->getSession()->getPage(); - - $form = $page->find('css', '#Form_EditForm'); - assertNotNull($form, 'I should see an edit page form'); - } - - /** - * @When /^I fill in content form with "([^"]*)"$/ - */ - public function stepIFillInContentFormWith($content) - { - $this->getSession()->evaluateScript("tinyMCE.get('Form_EditForm_Content').setContent('$content')"); - } - - /** - * @Then /^the content form should contain "([^"]*)"$/ - */ - public function theContentFormShouldContain($content) - { - $this->getMainContext()->assertElementContains('#Form_EditForm_Content', $content); - } -} diff --git a/features/bootstrap/SilverStripe/Test/Behaviour/CmsUiContext.php b/features/bootstrap/SilverStripe/Test/Behaviour/CmsUiContext.php deleted file mode 100644 index 5e021dc..0000000 --- a/features/bootstrap/SilverStripe/Test/Behaviour/CmsUiContext.php +++ /dev/null @@ -1,251 +0,0 @@ -context = $parameters; - } - - /** - * Get Mink session from MinkContext - */ - public function getSession($name = null) - { - return $this->getMainContext()->getSession($name); - } - - /** - * @Then /^I should see the CMS$/ - */ - public function iShouldSeeTheCms() - { - $page = $this->getSession()->getPage(); - $cms_element = $page->find('css', '.cms'); - assertNotNull($cms_element, 'CMS not found'); - } - - /** - * @Then /^I should see "([^"]*)" notice$/ - */ - public function iShouldSeeNotice($notice) - { - $this->getMainContext()->assertElementContains('.notice-wrap', $notice); - } - - /** - * @Then /^I should see "([^"]*)" message$/ - */ - public function iShouldSeeMessage($message) - { - $this->getMainContext()->assertElementContains('.message', $message); - } - - protected function getCmsTabsElement() - { - $this->getSession()->wait(5000, "window.jQuery('.cms-content-header-tabs').size() > 0"); - - $page = $this->getSession()->getPage(); - $cms_content_header_tabs = $page->find('css', '.cms-content-header-tabs'); - assertNotNull($cms_content_header_tabs, 'CMS tabs not found'); - - return $cms_content_header_tabs; - } - - protected function getCmsContentToolbarElement() - { - $this->getSession()->wait(5000, "window.jQuery('.cms-content-toolbar').size() > 0 && window.jQuery('.cms-content-toolbar').children().size() > 0"); - - $page = $this->getSession()->getPage(); - $cms_content_toolbar_element = $page->find('css', '.cms-content-toolbar'); - assertNotNull($cms_content_toolbar_element, 'CMS content toolbar not found'); - - return $cms_content_toolbar_element; - } - - protected function getCmsTreeElement() - { - $this->getSession()->wait(5000, "window.jQuery('.cms-tree').size() > 0"); - - $page = $this->getSession()->getPage(); - $cms_tree_element = $page->find('css', '.cms-tree'); - assertNotNull($cms_tree_element, 'CMS tree not found'); - - return $cms_tree_element; - } - - protected function getGridfieldTable($title) - { - $page = $this->getSession()->getPage(); - $table_elements = $page->findAll('css', '.ss-gridfield-table'); - assertNotNull($table_elements, 'Table elements not found'); - - $table_element = null; - foreach ($table_elements as $table) { - $table_title_element = $table->find('css', '.title'); - if ($table_title_element->getText() === $title) { - $table_element = $table; - break; - } - } - assertNotNull($table_element, sprintf('Table `%s` not found', $title)); - - return $table_element; - } - - /** - * @Given /^I should see "([^"]*)" button in CMS Content Toolbar$/ - */ - public function iShouldSeeButtonInCmsContentToolbar($text) - { - $cms_content_toolbar_element = $this->getCmsContentToolbarElement(); - - $element = $cms_content_toolbar_element->find('named', array('link_or_button', "'$text'")); - assertNotNull($element, sprintf('%s button not found', $text)); - } - - /** - * @When /^I should see "([^"]*)" in CMS Tree$/ - */ - public function stepIShouldSeeInCmsTree($text) - { - $cms_tree_element = $this->getCmsTreeElement(); - - $element = $cms_tree_element->find('named', array('content', "'$text'")); - assertNotNull($element, sprintf('%s not found', $text)); - } - - /** - * @When /^I should not see "([^"]*)" in CMS Tree$/ - */ - public function stepIShouldNotSeeInCmsTree($text) - { - $cms_tree_element = $this->getCmsTreeElement(); - - $element = $cms_tree_element->find('named', array('content', "'$text'")); - assertNull($element, sprintf('%s found', $text)); - } - - /** - * @When /^I expand Filter CMS Panel$/ - */ - public function iExpandFilterCmsPanel() - { - $page = $this->getSession()->getPage(); - - $panel_toggle_element = $page->find('css', '.cms-content > .cms-panel > .cms-panel-toggle > .toggle-expand'); - assertNotNull($panel_toggle_element, 'Panel toggle not found'); - - if ($panel_toggle_element->isVisible()) { - $panel_toggle_element->click(); - } - } - - /** - * @When /^I click the "([^"]*)" CMS tab$/ - */ - public function iClickTheCmsTab($tab) - { - $cms_tabs_element = $this->getCmsTabsElement(); - - $tab_element = $cms_tabs_element->find('named', array('link_or_button', "'$tab'")); - assertNotNull($tab_element, sprintf('%s tab not found', $tab)); - - $tab_element->click(); - } - - /** - * @Then /^the "([^"]*)" table should contain "([^"]*)"$/ - */ - public function theTableShouldContain($table, $text) - { - $table_element = $this->getGridfieldTable($table); - - $element = $table_element->find('named', array('content', "'$text'")); - assertNotNull($element, sprintf('Element containing `%s` not found in `%s` table', $text, $table)); - } - - /** - * @Then /^the "([^"]*)" table should not contain "([^"]*)"$/ - */ - public function theTableShouldNotContain($table, $text) - { - $table_element = $this->getGridfieldTable($table); - - $element = $table_element->find('named', array('content', "'$text'")); - assertNull($element, sprintf('Element containing `%s` not found in `%s` table', $text, $table)); - } - - /** - * @Given /^I click on "([^"]*)" in the "([^"]*)" table$/ - */ - public function iClickOnInTheTable($text, $table) - { - $table_element = $this->getGridfieldTable($table); - - $element = $table_element->find('xpath', sprintf('//*[count(*)=0 and contains(.,"%s")]', $text)); - assertNotNull($element, sprintf('Element containing `%s` not found', $text)); - $element->click(); - } - - /** - * @Then /^I can see the preview panel$/ - */ - public function iCanSeeThePreviewPanel() - { - $this->getMainContext()->assertElementOnPage('.cms-preview'); - } - - /** - * @Given /^the preview contains "([^"]*)"$/ - */ - public function thePreviewContains($content) - { - $driver = $this->getSession()->getDriver(); - $driver->switchToIFrame('cms-preview-iframe'); - - $this->getMainContext()->assertPageContainsText($content); - $driver->switchToWindow(); - } - - /** - * @Given /^the preview does not contain "([^"]*)"$/ - */ - public function thePreviewDoesNotContain($content) - { - $driver = $this->getSession()->getDriver(); - $driver->switchToIFrame('cms-preview-iframe'); - - $this->getMainContext()->assertPageNotContainsText($content); - $driver->switchToWindow(); - } -} diff --git a/features/bootstrap/SilverStripe/Test/Behaviour/LoginContext.php b/features/bootstrap/SilverStripe/Test/Behaviour/LoginContext.php deleted file mode 100644 index 083ee60..0000000 --- a/features/bootstrap/SilverStripe/Test/Behaviour/LoginContext.php +++ /dev/null @@ -1,150 +0,0 @@ -context = $parameters; - } - - /** - * Get Mink session from MinkContext - */ - public function getSession($name = null) - { - return $this->getMainContext()->getSession($name); - } - - /** - * @Given /^I am logged in$/ - */ - public function stepIAmLoggedIn() - { - $admin_url = $this->getMainContext()->joinUrlParts($this->getMainContext()->getBaseUrl(), $this->context['admin_url']); - $login_url = $this->getMainContext()->joinUrlParts($this->getMainContext()->getBaseUrl(), $this->context['login_url']); - - $this->getSession()->visit($admin_url); - - if (0 == strpos($this->getSession()->getCurrentUrl(), $login_url)) { - $this->stepILogInWith('admin', 'password'); - assertStringStartsWith($admin_url, $this->getSession()->getCurrentUrl()); - } - } - - /** - * @Given /^I am logged in with "([^"]*)" permissions$/ - */ - function iAmLoggedInWithPermissions($permCode) - { - if (!isset($this->cache_generatedMembers[$permCode])) { - $group = \Injector::inst()->create('Group'); - $group->Title = "$permCode group"; - $group->write(); - - $permission = \Injector::inst()->create('Permission'); - $permission->Code = $permCode; - $permission->write(); - $group->Permissions()->add($permission); - - $member = \DataObject::get_one('Member', sprintf('"Email" = \'%s\'', "$permCode@example.org")); - if (!$member) { - $member = \Injector::inst()->create('Member'); - } - - $member->FirstName = $permCode; - $member->Surname = "User"; - $member->Email = "$permCode@example.org"; - $member->changePassword('secret'); - $member->write(); - $group->Members()->add($member); - - $this->cache_generatedMembers[$permCode] = $member; - } - -// $this->cache_generatedMembers[$permCode]->logIn(); - return new Step\Given(sprintf('I log in with "%s" and "%s"', "$permCode@example.org", 'secret')); - } - - /** - * @Given /^I am not logged in$/ - */ - public function stepIAmNotLoggedIn() - { - $this->getSession()->reset(); - } - - /** - * @When /^I log in with "([^"]*)" and "([^"]*)"$/ - */ - public function stepILogInWith($email, $password) - { - $login_url = $this->getMainContext()->joinUrlParts($this->getMainContext()->getBaseUrl(), $this->context['login_url']); - - $this->getSession()->visit($login_url); - - $page = $this->getSession()->getPage(); - - $email_field = $page->find('css', '[name=Email]'); - $password_field = $page->find('css', '[name=Password]'); - $submit_button = $page->find('css', '[type=submit]'); - $email_field->setValue($email); - $password_field->setValue($password); - $submit_button->press(); - } - - /** - * @Given /^I should see a log-in form$/ - */ - public function stepIShouldSeeALogInForm() - { - $page = $this->getSession()->getPage(); - - $login_form = $page->find('css', '#MemberLoginForm_LoginForm'); - assertNotNull($login_form, 'I should see a log-in form'); - } - - /** - * @Then /^I will see a bad log-in message$/ - */ - public function stepIWillSeeABadLogInMessage() - { - $page = $this->getSession()->getPage(); - - $bad_message = $page->find('css', '.message.bad'); - - assertNotNull($bad_message, 'Bad message not found.'); - } -} diff --git a/features/bootstrap/SilverStripe/Test/Behaviour/SilverStripeContext.php b/features/bootstrap/SilverStripe/Test/Behaviour/SilverStripeContext.php deleted file mode 100644 index b90b02a..0000000 --- a/features/bootstrap/SilverStripe/Test/Behaviour/SilverStripeContext.php +++ /dev/null @@ -1,444 +0,0 @@ -context = $parameters; - } - - public function setDatabase($database_name) - { - $this->database_name = $database_name; - } - - public function setAjaxEnabledSteps($ajax_steps) - { - if (empty($ajax_steps)) { - $ajax_steps = array(); - } - $this->ajax_steps = $ajax_steps; - } - - public function getAjaxEnabledSteps() - { - return $this->ajax_steps; - } - - public function getFixture($data_object) - { - if (!array_key_exists($data_object, $this->fixtures)) { - throw new \OutOfBoundsException(sprintf('Data object `%s` does not exist!', $data_object)); - } - - return $this->fixtures[$data_object]; - } - - public function getFixtures() - { - return $this->fixtures; - } - - /** - * @BeforeScenario - */ - public function before(ScenarioEvent $event) - { - if (!isset($this->database_name)) { - throw new \LogicException('Context\'s $database_name has to be set when implementing SilverStripeAwareContextInterface.'); - } - - $setdb_url = $this->joinUrlParts($this->getBaseUrl(), '/dev/tests/setdb'); - $setdb_url = sprintf('%s?database=%s', $setdb_url, $this->database_name); - $this->getSession()->visit($setdb_url); - } - - /** - * @BeforeScenario @database-defaults - */ - public function beforeDatabaseDefaults(ScenarioEvent $event) - { - \SapphireTest::empty_temp_db(); - global $databaseConfig; - \DB::connect($databaseConfig); - $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->created_files_paths)) { - $created_files = array_reverse($this->created_files_paths); - foreach ($created_files 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($data_object, PyStringNode $string) - { - if (!is_array($this->fixtures)) { - $this->fixtures = array(); - } - if (!is_array($this->fixtures_lazy)) { - $this->fixtures_lazy = array(); - } - if (!isset($this->files_path)) { - $this->files_path = realpath($this->getMinkParameter('files_path')); - } - if (!is_array($this->created_files_paths)) { - $this->created_files_paths = array(); - } - - if (array_key_exists($data_object, $this->fixtures)) { - throw new \InvalidArgumentException(sprintf('Data object `%s` already exists!', $data_object)); - } - - $fixture = array_merge(array($data_object . ':'), $string->getLines()); - $fixture = implode("\n ", $fixture); - - if ('Folder' === $data_object) { - $this->prepareTestAssetsDirectories($fixture); - } - - if ('File' === $data_object) { - $this->prepareTestAssetsFiles($fixture); - } - - $fixtures_lazy = array($data_object => array()); - if (preg_match('/=>(\w+)/', $fixture)) { - $fixture_content = Yaml::parse($fixture); - foreach ($fixture_content[$data_object] as $identifier => &$fields) { - foreach ($fields as $field_val) { - if (substr($field_val, 0, 2) == '=>') { - $fixtures_lazy[$data_object][$identifier] = $fixture_content[$data_object][$identifier]; - unset($fixture_content[$data_object][$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] !== $data_object) { -// $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[$data_object] = new \YamlFixture($fixture); - $model = \DataModel::inst(); - $this->fixtures[$data_object]->saveIntoDatabase($model); - // Lazy load fixtures into database - // Loop is required for nested lazy fixtures - foreach ($fixtures_lazy[$data_object] as $identifier => $fields) { - $fixture = array( - $data_object => array( - $identifier => $fields, - ), - ); - $fixture = Yaml::dump($fixture); - $fixture = preg_replace_callback('/=>(\w+)\.([\w.]+)/', array($this, 'replaceFixtureReferences'), $fixture); - $this->fixtures_lazy[$data_object][$identifier] = new \YamlFixture($fixture); - $this->fixtures_lazy[$data_object][$identifier]->saveIntoDatabase($model); - } - } - - 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->files_path)); - } - - \Filesystem::makeFolder($folder_path); - $this->created_files_paths[] = $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/')); - } - - $file_path = $this->files_path . DIRECTORY_SEPARATOR . basename($value); - if (!file_exists($file_path) || !is_file($file_path)) { - throw new \Exception(sprintf('`%s` does not exist or is not a file', $this->files_path)); - } - $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->files_path)); - } - - if (!file_exists($asset_path)) { - if (@copy($file_path, $asset_path)) { - $this->created_files_paths[] = $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($class_name, $identifier) - { - if (false !== ($id = $this->fixtures[$class_name]->idFromFixture($class_name, $identifier))) { - return $id; - } - if (isset($this->fixtures_lazy[$class_name], $this->fixtures_lazy[$class_name][$identifier]) && - false !== ($id = $this->fixtures_lazy[$class_name][$identifier]->idFromFixture($class_name, $identifier))) { - return $id; - } - - throw new \OutOfBoundsException(sprintf('`%s` identifier in Data object `%s` does not exist!', $identifier, $class_name)); - } - - /** - * Parses given URL and returns its components - * - * @param $url - * @return array|mixed Parsed URL - */ - public function parseUrl($url) - { - $url = parse_url($url); - $url['vars'] = array(); - if (!isset($url['fragment'])) { - $url['fragment'] = null; - } - if (isset($url['query'])) { - parse_str($url['query'], $url['vars']); - } - - return $url; - } - - /** - * Checks whether current URL is close enough to the given URL. - * Unless specified in $url, get vars will be ignored - * Unless specified in $url, fragment identifiers will be ignored - * - * @param $url string URL to compare to current URL - * @return boolean Returns true if the current URL is close enough to the given URL, false otherwise. - */ - public function isCurrentUrlSimilarTo($url) - { - $current = $this->parseUrl($this->getSession()->getCurrentUrl()); - $test = $this->parseUrl($url); - - if ($current['path'] !== $test['path']) { - return false; - } - - if (isset($test['fragment']) && $current['fragment'] !== $test['fragment']) { - return false; - } - - foreach ($test['vars'] as $name => $value) { - if (!isset($current['vars'][$name]) || $current['vars'][$name] !== $value) { - return false; - } - } - - return true; - } - - /** - * Returns base URL parameter set in MinkExtension. - * It simplifies configuration by allowing to specify this parameter - * once but makes code dependent on MinkExtension. - * - * @return string - */ - public function getBaseUrl() - { - return $this->getMinkParameter('base_url') ?: ''; - } - - /** - * Joins URL parts into an URL using forward slash. - * Forward slash usages are normalised to one between parts. - * This method takes variable number of parameters. - * - * @param $... - * @return string - * @throws \InvalidArgumentException - */ - public function joinUrlParts() - { - if (0 === func_num_args()) { - throw new \InvalidArgumentException('Need at least one argument'); - } - - $parts = func_get_args(); - $trim_slashes = function(&$part) { - $part = trim($part, '/'); - }; - array_walk($parts, $trim_slashes); - - return implode('/', $parts); - } - - public function canIntercept() - { - $driver = $this->getSession()->getDriver(); - if ($driver instanceof GoutteDriver) { - return true; - } - else { - if ($driver instanceof Selenium2Driver) { - return false; - } - } - - throw new UnsupportedDriverActionException('You need to tag the scenario with "@mink:goutte" or "@mink:symfony". Intercepting the redirections is not supported by %s', $driver); - } - - /** - * @Given /^(.*) without redirection$/ - */ - public function theRedirectionsAreIntercepted($step) - { - if ($this->canIntercept()) { - $this->getSession()->getDriver()->getClient()->followRedirects(false); - } - - return new Step\Given($step); - } - - /** - * @Given /^((?:I )fill in =>(.+?) for "([^"]*)")$/ - */ - public function iFillInFor($step, $reference, $field) - { - if (false === strpos($reference, '.')) { - throw new \Exception('Fixture reference should be in following format: =>ClassName.identifier'); - } - - list($class_name, $identifier) = explode('.', $reference); - $id = $this->idFromFixture($class_name, $identifier); - //$step = preg_replace('#=>(.+?) for "([^"]*)"#', '"'.$id.'" for "'.$field.'"', $step); - - // below is not working, because Selenium can't interact with hidden inputs - // return new Step\Given($step); - - // TODO: investigate how to simplify this and make universal - $javascript = <<getSession()->executeScript($javascript); - } - - /** - * @Given /^((?:I )fill in "([^"]*)" with =>(.+))$/ - */ - public function iFillInWith($step, $field, $reference) - { - if (false === strpos($reference, '.')) { - throw new \Exception('Fixture reference should be in following format: =>ClassName.identifier'); - } - - list($class_name, $identifier) = explode('.', $reference); - $id = $this->idFromFixture($class_name, $identifier); - //$step = preg_replace('#"([^"]*)" with =>(.+)#', '"'.$field.'" with "'.$id.'"', $step); - - // below is not working, because Selenium can't interact with hidden inputs - // return new Step\Given($step); - - // TODO: investigate how to simplify this and make universal - $javascript = <<getSession()->executeScript($javascript); - } -} diff --git a/features/bootstrap/SubContext.php.template b/features/bootstrap/SubContext.php.template deleted file mode 100644 index fa4f538..0000000 --- a/features/bootstrap/SubContext.php.template +++ /dev/null @@ -1,45 +0,0 @@ -context = $parameters; - } - - /** - * Get Mink session from MinkContext - */ - public function getSession($name = null) - { - return $this->getMainContext()->getSession($name); - } - /** - * Write your subcontext methods below. - * Remember that this class extends BehatContext, not MinkContext - */ -} diff --git a/features/create-a-page.feature b/features/create-a-page.feature deleted file mode 100644 index 84652be..0000000 --- a/features/create-a-page.feature +++ /dev/null @@ -1,15 +0,0 @@ -@database-defaults -Feature: Create a page - As an author - I want to create a page in the CMS - So that I can grow my website - - @javascript - Scenario: I can create a page from the pages section - Given I am logged in with "ADMIN" permissions - And I go to "/admin/pages" - And I should see "Add new" button in CMS Content Toolbar - When I press "Add new" button - And I check "Page" - And I press "Create" button - Then I should see an edit page form diff --git a/features/edit-a-page.feature b/features/edit-a-page.feature deleted file mode 100644 index 79e7411..0000000 --- a/features/edit-a-page.feature +++ /dev/null @@ -1,29 +0,0 @@ -@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 I am logged in with "ADMIN" permissions - And I go to "/admin/pages" - Then I should see "About Us" in CMS Tree - - @javascript - Scenario: I can open a page for editing from the pages tree - When I follow "About Us" - Then I should see an edit page form - - @javascript - Scenario: I can edit title and content and see the changes on draft - When I follow "About Us" - Then I should see an edit page form - - When I fill in "Title" with "About Us!" - And I fill in content form with "my new content" - And I press "Save Draft" button - Then I should see "Saved." notice - - When I follow "About Us" - Then the "Title" field should contain "About Us!" - And the content form should contain "my new content" \ No newline at end of file diff --git a/features/files/file1.jpg b/features/files/file1.jpg deleted file mode 100644 index beb5a91..0000000 Binary files a/features/files/file1.jpg and /dev/null differ diff --git a/features/files/file2.jpg b/features/files/file2.jpg deleted file mode 100644 index f17a4ec..0000000 Binary files a/features/files/file2.jpg and /dev/null differ diff --git a/features/files/testfile.jpg b/features/files/testfile.jpg deleted file mode 100644 index 5e128e4..0000000 Binary files a/features/files/testfile.jpg and /dev/null differ diff --git a/features/login.feature b/features/login.feature deleted file mode 100644 index b7a8388..0000000 --- a/features/login.feature +++ /dev/null @@ -1,20 +0,0 @@ -# features/login.feature -Feature: Log in - As an site owner - I want to access to the CMS to be secure - So that only my team can make content changes - - Scenario: Bad login - Given I log in with "bad@example.com" and "badpassword" - Then I will see a bad log-in message - - Scenario: Valid login - Given I am logged in with "ADMIN" permissions - When I go to "/admin/" - Then I should see the CMS - - Scenario: /admin/ redirect for not logged in user - # disable automatic redirection so we can use the profiler - When I go to "/admin/" without redirection - Then I should be redirected to "/Security/login" - And I should see a log-in form \ No newline at end of file diff --git a/features/manage-files.feature b/features/manage-files.feature deleted file mode 100644 index 2c3efda..0000000 --- a/features/manage-files.feature +++ /dev/null @@ -1,84 +0,0 @@ -@javascript @assets -Feature: Manage files - As a cms author - I want to upload and manage files within the CMS - 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 - """ - 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 - Scenario: I can add a new folder - Given I press "Add folder" button - And I type "newfolder" into the dialog - And I confirm the dialog - Then the "Files" table should contain "newfolder" - - Scenario: I can list files in a folder - Given I click on "folder1" in the "Files" table - Then the "folder1" table should contain "file1" - And the "folder1" table should not contain "file1.1" - - Scenario: I can upload a file to a folder - Given I click on "folder1" in the "Files" table - And I press "Upload" button - And I attach the file "testfile.jpg" to "AssetUploadField" with HTML5 - And I wait for "5000" - And I press "Back to folder" button - Then the "folder1" table should contain "testfile" - - Scenario: I can edit a file - Given I click on "folder1" in the "Files" table - And I click on "file1" in the "folder1" table - And I fill in "renamedfile" for "Title" - And I press "Save" button - And I press "Back" button - Then the "folder1" table should not contain "testfile" - And the "folder1" table should contain "renamedfile" - - Scenario: I can delete a file - Given I click on "folder1" in the "Files" table - And I click on "file1" in the "folder1" table - And I press "Delete" button - Then the "folder1" table should not contain "file1" - - 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 press "Save" button - # /show/0 is to ensure that we are on top level folder - And I go to "/admin/assets/show/0" - And I click on "folder2" in the "Files" table - And the "folder2" table should contain "file1" \ No newline at end of file diff --git a/features/manage-users.feature b/features/manage-users.feature deleted file mode 100644 index 0ef02fc..0000000 --- a/features/manage-users.feature +++ /dev/null @@ -1,87 +0,0 @@ -@database-defaults -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 - """ - 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 - And I click "Admin Group" in the "#Root_Groups" 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 - - @javascript - Scenario: I can add a user to the system - When I click the "Users" CMS tab - And I press "Add Member" button - And I fill in the following: - | First Name | John | - | Surname | Doe | - | Email | john.doe@test.com | - And I press "Create" button - Then I should see "Saved member" message - - 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 "Save" button - Then I should see "Saved Member" message - - When I go to "admin/security" - And I click the "Groups" CMS tab - 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 - And I press "Delete" button - Then I should see "admin@test.com" - And I should not see "staffmember@test.com" \ No newline at end of file diff --git a/features/preview-a-page.feature b/features/preview-a-page.feature deleted file mode 100644 index 1ca2a5c..0000000 --- a/features/preview-a-page.feature +++ /dev/null @@ -1,41 +0,0 @@ -@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 - - @javascript - Scenario: I can show a preview of the current page from the pages section - Given I am logged in with "ADMIN" permissions - And I go to "/admin/pages" - Then I should see "About Us" in CMS Tree - - When I follow "About Us" - And I press "Preview »" button - Then I can see the preview panel - And the preview contains "About Us" - - # TODO: - # - Only tests correctly on fresh database - # - We should continue testing against it after we have fixtures ready - @javascript - Scenario: I can see an updated preview when editing content - Given I am logged in with "ADMIN" permissions - And I go to "/admin/pages" - Then I should see "About Us" in CMS Tree - - When I follow "About Us" - And I fill in content form with "my new content" - And I press "Save Draft" button - And I press "Preview »" button - - When I follow "Published Site" - Then the preview does not contain "my new content" - And the preview contains "You can fill" - - When I follow "Draft Site" - Then the preview does not contain "You can fill" - And the preview contains "my new content" - - When I press "« Edit" button - Then I should see an edit page form \ No newline at end of file diff --git a/features/publish-a-page.feature b/features/publish-a-page.feature deleted file mode 100644 index ee7e106..0000000 --- a/features/publish-a-page.feature +++ /dev/null @@ -1,4 +0,0 @@ -Feature: Create a page - As a site owner - I want content to go to a draft site before being published - So that only high quality changes are seen by our visitors \ No newline at end of file diff --git a/features/search-for-a-page.feature b/features/search-for-a-page.feature deleted file mode 100644 index b519781..0000000 --- a/features/search-for-a-page.feature +++ /dev/null @@ -1,18 +0,0 @@ -@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 - - @javascript - Scenario: I can search for a page by its title - Given I am logged in with "ADMIN" permissions - And I go to "/admin/pages" - Then I should see "About Us" in CMS Tree - And I should see "Contact Us" in CMS Tree - - When I expand Filter CMS Panel - And I fill in "Content" with "About Us" - And I press "Apply Filter" button - Then I should see "About Us" in CMS Tree - But I should not see "Contact Us" in CMS Tree