diff --git a/admin/javascript/LeftAndMain.Preview.js b/admin/javascript/LeftAndMain.Preview.js index 35c84502e..d4c01419d 100644 --- a/admin/javascript/LeftAndMain.Preview.js +++ b/admin/javascript/LeftAndMain.Preview.js @@ -160,6 +160,8 @@ // Load edit view for new page, but only if the preview is activated at the moment. // This avoids e.g. force-redirections of the edit view on RedirectorPage instances. self._loadCurrentPage(); + + $(this).removeClass('loading'); }); // Preview might not be available in all admin interfaces - block/disable when necessary @@ -226,7 +228,7 @@ * Change the URL of the preview iframe. */ _loadUrl: function(url) { - this.find('iframe').attr('src', url); + this.find('iframe').addClass('loading').attr('src', url); return this; }, 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 85200c835..42d2b2e73 100644 --- a/tests/behat/features/bootstrap/SilverStripe/Framework/Test/Behaviour/CmsUiContext.php +++ b/tests/behat/features/bootstrap/SilverStripe/Framework/Test/Behaviour/CmsUiContext.php @@ -6,7 +6,8 @@ use Behat\Behat\Context\ClosuredContextInterface, Behat\Behat\Context\TranslatedContextInterface, Behat\Behat\Context\BehatContext, Behat\Behat\Context\Step, - Behat\Behat\Exception\PendingException; + Behat\Behat\Exception\PendingException, + Behat\Mink\Exception\ElementNotFoundException; use Behat\Gherkin\Node\PyStringNode, Behat\Gherkin\Node\TableNode; @@ -250,6 +251,52 @@ class CmsUiContext extends BehatContext $driver->switchToWindow(); } + /** + * @Given /^I set the CMS mode to "([^"]*)"$/ + */ + public function iSetTheCmsToMode($mode) + { + return array( + new Step\When(sprintf('I fill in the "Change view mode" dropdown with "%s"', $mode)), + new Step\When('I wait for 1 second') // wait for CMS layout to redraw + ); + } + + /** + * @Given /^I wait for the preview to load$/ + */ + public function iWaitForThePreviewToLoad() + { + $driver = $this->getSession()->getDriver(); + $driver->switchToIFrame('cms-preview-iframe'); + + $this->getSession()->wait( + 5000, + "!jQuery('iframe[name=cms-preview-iframe]').hasClass('loading')" + ); + + $driver->switchToWindow(); + } + + /** + * @Given /^I switch the preview to "([^"]*)"$/ + */ + public function iSwitchThePreviewToMode($mode) + { + $controls = $this->getSession()->getPage()->find('css', '.cms-preview-controls'); + assertNotNull($controls, 'Preview controls not found'); + + $label = $controls->find('xpath', sprintf( + './/label[(@for="%s")]', + $mode + )); + assertNotNull($label, 'Preview mode switch not found'); + + $label->click(); + + return new Step\When('I wait for the preview to load'); + } + /** * @Given /^the preview does not contain "([^"]*)"$/ */ @@ -265,38 +312,75 @@ class CmsUiContext extends BehatContext /** * Workaround for chosen.js dropdowns which hide the original dropdown field. * - * @When /^(?:|I )fill in "(?P(?:[^"]|\\")*)" dropdown with "(?P(?:[^"]|\\")*)"$/ - * @When /^(?:|I )fill in "(?P(?:[^"]|\\")*)" for "(?P(?:[^"]|\\")*)" dropdown$/ + * @When /^(?:|I )fill in the "(?P(?:[^"]|\\")*)" dropdown with "(?P(?:[^"]|\\")*)"$/ + * @When /^(?:|I )fill in "(?P(?:[^"]|\\")*)" for the "(?P(?:[^"]|\\")*)" dropdown$/ */ public function theIFillInTheDropdownWith($field, $value) { $field = $this->fixStepArgument($field); $value = $this->fixStepArgument($value); - $inputField = $this->getSession()->getPage()->findField($field); - if(null === $inputField) { - throw new ElementNotFoundException(sprintf( - 'Chosen.js dropdown named "%s" not found', - $field - )); + // Given the fuzzy matching, we might get more than one matching field. + $formFields = array(); + + // Find by label + $formField = $this->getSession()->getPage()->findField($field); + if($formField) $formFields[] = $formField; + + // Fall back to finding by title (for dropdowns without a label) + if(!$formFields) { + $formFields = $this->getSession()->getPage()->findAll( + 'xpath', + sprintf( + '//*[self::select][(./@title="%s")]', + $field + ) + ); } - $container = $inputField->getParent()->getParent(); - if(null === $container) throw new ElementNotFoundException('Chosen.js field container not found'); + assertGreaterThan(0, count($formFields), sprintf( + 'Chosen.js dropdown named "%s" not found', + $field + )); + + $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; + } + } - $linkEl = $container->find('xpath', './/a'); - if(null === $linkEl) throw new ElementNotFoundException('Chosen.js link element not found'); - $linkEl->click(); + assertGreaterThan(0, count($containers), 'Chosen.js field container not found'); + + // Default to first visible container + $container = $containers[0]; + + // Click on newly expanded list element, indirectly setting the dropdown value + $linkEl = $container->find('xpath', './/a[./@href]'); + assertNotNull($linkEl, 'Chosen.js link element not found'); $this->getSession()->wait(100); // wait for dropdown overlay to appear + $linkEl->click(); $listEl = $container->find('xpath', sprintf('.//li[contains(normalize-space(string(.)), \'%s\')]', $value)); - if(null === $listEl) - { - throw new ElementNotFoundException(sprintf( - 'Chosen.js list element with title "%s" not found', - $value - )); - } + assertNotNull($listEl, 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(); }