diff --git a/.ez.yml b/.ez.yml new file mode 100644 index 0000000..14db8d8 --- /dev/null +++ b/.ez.yml @@ -0,0 +1,14 @@ +v: 0 + +# This is a bundle, so we need to specify info for meta repo +meta: + repo: "git@github.com:ezsystems/ezplatform-ee-demo.git" + branch: "master" + self_alias: "1.10.x-dev" + +# ci +integrate: + command: "bin/behat" + matrix: + # Run 'common' tagged behat scenarios on ezplatform-ee-demo install + - {arguments: "-v --profile contentOnTheFly --strict", install: "demo"} diff --git a/behat_suites.yml b/behat_suites.yml index e69de29..a2a8995 100644 --- a/behat_suites.yml +++ b/behat_suites.yml @@ -0,0 +1,9 @@ +contentOnTheFly: + suites: + Standard: + paths: [ vendor/ezsystems/content-on-the-fly-prototype/bundle/Features ] + filters: + tags: common + contexts: + - EzSystems\FlexWorkflowBundle\Features\Context\FlexWf + - EzSystems\EzContentOnTheFlyBundle\Features\Context\ContentOnTheFlyContext diff --git a/bundle/Features/ContentOnTheFly.feature b/bundle/Features/ContentOnTheFly.feature new file mode 100644 index 0000000..ee57309 --- /dev/null +++ b/bundle/Features/ContentOnTheFly.feature @@ -0,0 +1,70 @@ +Feature: Basic interactions for ContentOnTheFly + + Background: + Given I am logged in as admin on StudioUI + + @javascript @common @contentOnTheFly + Scenario: I can create Content directly from the Dashboard + Given I start creating content from the Dashboard + And I create Article from Content group in "Home/Places & Tastes/Tastes" location + And I fill in basic Article data + When I click the edit action bar button Publish + Then I can create another content + + @javascript @common @contentOnTheFly @flex + Scenario: I can create Content directly from the Dashboard and send it for review + Given I start creating content from the Dashboard + And I create Article from Content group in "/Media" location + And I fill in basic Article data + And I make a modification to Title and send it for review + And I select reviewer "Yura Rajzer" + When I confirm sending for review + Then I can create another content + + @javascript @common @contentOnTheFly + Scenario: I can create Content from the Universal Discovery widget + Given I click on the navigation zone "Content" + And I click on the navigation item "Content structure" + And I click on the discovery bar button "Content browse" + And I start creating content from the Universal Discovery widget + And I create Gallery from Media group in "/Media" location + And I fill in Name with "Gallery Title" + When I click the edit action bar button Publish + Then I can create another content + + @javascript @common @contentOnTheFly + Scenario: I can create embedded Content while creating another Content + Given I start creating content from the Dashboard + And I select Article from the Content group + And I finish configuration + And I choose Embed for the Summary block + And I start creating content from the Universal Discovery widget + And I create Article from Content group in "Home/Places & Tastes" location + And I fill in basic Article data + And I click the edit action bar button Publish + And I see embedded content in Summary section + When I click the edit action bar button Publish + Then I can create another content + + @javascript @common @contentOnTheFly + Scenario: I can create embedded Content while configuring a Block + Given I go to Studio creator and prepare for "Embed" block + And I set up the Embed block element in the landing page zone first + And I click on the pop-up form button Content + And I start creating content from the Universal Discovery widget + And I create "Blog post" from Content group in "Home/Places & Tastes" location + And I fill in basic Blog post data + And I click the edit action bar button Publish + When I submit the block pop-up form + Then I see the Embed block with Article and its preview in first zone + + @javascript @fullRegression @contentOnTheFly + Scenario: I can change Content Type after selecting it + Given I start creating content from the Dashboard + And I select Article from the Content group + And I change Content Type to Gallery from Media group + And I select "/Media" from Suggested Locations + And I finish configuration + And I fill in Name with "Gallery Title" + When I click the edit action bar button Publish + Then I can create another content diff --git a/bundle/Features/Context/ContentOnTheFlyContext.php b/bundle/Features/Context/ContentOnTheFlyContext.php new file mode 100644 index 0000000..f365b5d --- /dev/null +++ b/bundle/Features/Context/ContentOnTheFlyContext.php @@ -0,0 +1,136 @@ +getEnvironment(); + $this->flexWfContext = $environment->getContext('EzSystems\FlexWorkflowBundle\Features\Context\FlexWf'); + } + + /** + * @Given I start creating content from the Dashboard + * + * Click the "Create" button when ot the Dashboard + */ + public function startCreatingContentFromDashboard() + { + $parentSelector = ContentOnTheFlyPopup::getParentSelector('Dashboard'); + $this->contentOnTheFly = new ContentOnTheFlyPopup($this->flexWfContext, $parentSelector); + $this->flexWfContext->clickElementByText('CREATE', 'button'); + } + + /** + * @Given I start creating content from the Universal Discovery widget + * + * Switches to embedded Content On The Fly window when UDW is open + */ + public function startCreatingContentFromUDW() + { + $parentSelector = ContentOnTheFlyPopup::getParentSelector('UDW'); + $this->contentOnTheFly = new ContentOnTheFlyPopup($this->flexWfContext, $parentSelector); + $this->flexWfContext->switchContentBrowserTab('Create'); + } + + /** + * @Given I create :contentType from :contentGroup group in :location location + * + * Selects Content Type and location (if available - from Suggested locations) in open Content On The Fly Popup + * + * @param string $contentGroup Name of the Content Group to which Content Type belongs + * @param string $contentType Name of the Content Type + * @param string $location Location of the content + */ + public function createNewContentInLocation($contentGroup, $contentType, $location) + { + $this->chooseContentType($contentGroup, $contentType); + if (in_array($location, $this->contentOnTheFly->displayedSuggestedLocations)) { + $this->selectFromSuggestedLocation($location); + } else { + $this->selectLocation($location); + } + $this->finishConfiguration(); + } + + /** + * @Given I select :contentType from the :contentGroup group + * + * Selects given Content Type (checks Content Group if needed) + * + * @param string $contentGroup Name of the Content Group to which Content Type belongs + * @param string $contentType Name of the Content Type + */ + public function chooseContentType($contentGroup, $contentType) + { + $this->contentOnTheFly->chooseContentType($contentGroup, $contentType); + $this->contentOnTheFly->clickButton('next'); + } + + /** + * @Given I select :location from Suggested Locations + * + * Select a location from available suggested Locations + * + * @param string $location Location to select + */ + public function selectFromSuggestedLocation($location) + { + $this->contentOnTheFly->selectSuggestedLocation($location); + } + + /** + * @Given I change Content Type to :contentType from :contentGroup group + * + * Undo selecting a Content Type and select another one + * + * @param string $contentGroup Name of the Content Group to which Content Type belongs + * @param string $contentType Name of the Content Type to select + */ + public function changeContentType($contentGroup, $contentType) + { + $this->contentOnTheFly->removeContentType(); + $this->contentOnTheFly->chooseContentType($contentGroup, $contentType); + $this->contentOnTheFly->clickButton('next'); + } + + /** + * @Given I select :location location + * + * Select given location using UDW + * + * @param string $location Location to select + */ + public function selectLocation($location) + { + $this->contentOnTheFly->selectLocation($location); + } + + /** + * @Given I finish configuration + * + * Clicks "Finish" button + */ + public function finishConfiguration() + { + $this->contentOnTheFly->waitUntilSelectedLocationIsDisplayed($this->contentOnTheFly->selectedLocation); + $this->contentOnTheFly->clickButton('finish'); + } +} diff --git a/bundle/Features/Context/ContentOnTheFlyPopup.php b/bundle/Features/Context/ContentOnTheFlyPopup.php new file mode 100644 index 0000000..29a18b9 --- /dev/null +++ b/bundle/Features/Context/ContentOnTheFlyPopup.php @@ -0,0 +1,184 @@ + ".ez-view-dashboardblocksview", + "UDW" => ".ez-view-universaldiscoveryview", + ]; + + /** + * @param \EzSystems\StudioUIBundle\Features\Context\StudioUI $context + * @param string $parentSelector Selector of the element contaning Content Of The Fly in it + */ + public function __construct(StudioUI $context, $parentSelector) + { + $this->context = $context; + $this->mainSelector = sprintf('%s %s', $parentSelector, $this->mainSelector); + $this->context->waitWhileLoading(); + } + + /** + * Content on the fly can be embedded in different DOM nodes. Returns selector to interact with the correct one. + * + * @param string $parentLocation Location from which Content On The Fly is invoked + * + * @throws InvalidArgumentException If unknown parent location is given + * + * @return string Parent selector of the invoked Content On The Fly popup + */ + public static function getParentSelector($parentLocation) + { + if (!array_key_exists($parentLocation, self::$parentLocations)) { + throw new InvalidArgumentException('Unsupported parent location: ' . $parentLocation); + } + + return self::$parentLocations[$parentLocation]; + } + + /** + * Selects the Content type from given Content Group. Selects the Content group if needed. + * + * @param string $contentGroup Name of the Content Group + * @param string $contentType Name of the Content Type + */ + public function chooseContentType($contentGroup, $contentType) + { + $element = $this->context->getElementByText($contentGroup, '.ez-contenttypeselector-group'); + + if (!$this->context->findWithWait('.ez-contenttypeselector-group-checkbox', $element)->isChecked()) { + $element->click(); + } + + $this->context->clickElementByText($contentType, '.ez-selection-filter-item'); + $this->selectedContentType = $contentType; + } + + /** + * Clicks the button in content on the fly button. + * + * @param string $button Button to click: next, finish or select + */ + public function clickButton($button) + { + $this->context->clickElementByClass(sprintf('%s %s--%s', $this->mainSelector, $this->buttonSelector, $button)); + } + + /** + * Selects a location from suggested locations dropdown. + * + * @param string $location Location to select from suggested locations + */ + public function selectSuggestedLocation($location) + { + $this->context->spin(function () { + return $this->areSuggestedLocationsLoaded(); + }); + $this->clickButton('select'); + $this->context->clickElementByText($location, $this->suggestedLocationsListSelector); + + $this->waitUntilSelectedLocationIsDisplayed($location); + $this->selectedLocation = $location; + } + + /** + * Verifies whether suggested locations have been loaded correctly. + * + * @return bool + */ + public function areSuggestedLocationsLoaded() + { + return count($this->displayedSuggestedLocations) === count($this->context->findAllWithWait($this->suggestedLocationsListSelector)); + } + + /** + * Select locations using Universal Discovery Widget. + * + * @param string $location Location to select from UDW + */ + public function selectLocation($location) + { + $this->context->clickElementByText($this->selectLocationText, $this->buttonSelector); + $this->context->selectFromUniversalDiscovery($location); + $this->context->clickChooseContentPopUp('Confirm selection'); + $this->context->waitWhileLoading(); + + $this->waitUntilSelectedLocationIsDisplayed($location); + $this->selectedLocation = $location; + } + + /** + * Removes the selected Content Type. + */ + public function removeContentType() + { + $selectedContentType = $this->context->getElementByClass(sprintf('%s %s', $this->mainSelector, $this->changeContentTypeButton)); + PHPUnit_Framework_Assert::assertSame($this->selectedContentType, $selectedContentType->getText()); + $selectedContentType->click(); + } + + /** + * Gets displayed selected location. + * + * @return string Displayed selected location + */ + public function getDisplayedSelectedLocation() + { + return $this->context->findWithWait(sprintf('%s %s', $this->mainSelector, $this->displayedLocationSelector))->getText(); + } + + /** + * Waits until the displayed location is the same as set by the user + * + * @param string $location Expected selected location + */ + public function waitUntilSelectedLocationIsDisplayed($location) + { + $location = substr($location, 0, 1) === '/' ? $location : sprintf('/%s', $location); + $this->context->spin( + function () use ($location) { + return $this->getDisplayedSelectedLocation() === $location; + } + ); + } +}