From be6885a70ccf224710446a7b257fca118e117362 Mon Sep 17 00:00:00 2001 From: Miguel Jacinto Date: Tue, 11 Oct 2016 14:58:50 +0100 Subject: [PATCH 1/5] [Behat] Remove element fetching using text value from CommonActions --- .../Context/SubContext/Authentication.php | 3 +- Features/Context/SubContext/CommonActions.php | 92 ++++++++++++++----- 2 files changed, 73 insertions(+), 22 deletions(-) diff --git a/Features/Context/SubContext/Authentication.php b/Features/Context/SubContext/Authentication.php index 7de22db27..d90712a14 100644 --- a/Features/Context/SubContext/Authentication.php +++ b/Features/Context/SubContext/Authentication.php @@ -35,7 +35,8 @@ public function goToPlatformUiAndLogIn($username, $password) $this->waitWhileLoading(); $this->fillFieldWithValue('username', $username); $this->fillFieldWithValue('password', $password); - $this->iClickAtButton('Login'); + $loginButton = $this->findWithWait('.ez-loginform-button'); + $loginButton->click(); $this->iShouldBeLoggedIn(); $this->shouldBeLoggedIn = true; } diff --git a/Features/Context/SubContext/CommonActions.php b/Features/Context/SubContext/CommonActions.php index 5e862a235..0329bd94a 100644 --- a/Features/Context/SubContext/CommonActions.php +++ b/Features/Context/SubContext/CommonActions.php @@ -22,6 +22,7 @@ trait CommonActions public function iClickAtLink($link) { $this->clickElementByText($link, 'a'); + // @TODO implement click on link without get by text } /** @@ -33,6 +34,7 @@ public function iClickAtLink($link) public function iClickAtButton($button) { $this->clickElementByText($button, 'button'); + // @TODO implement click on link without get by text } /** @@ -152,6 +154,7 @@ public function clickLogo() public function clickTab($tab) { $this->clickElementByText($tab, '.ez-tabs-label a[href]'); + // @TODO implement without get by text } /** @@ -162,7 +165,15 @@ public function clickTab($tab) */ public function clickNavigationZone($zone) { - $this->clickElementByText($zone, '.ez-zone-name'); + $dataNavigation = [ + 'Content' => 'platform', + 'Page' => 'studio', + 'Performance' => 'studioplus', + 'Admin Panel' => 'admin', + ]; + $dataNavigationValue = $dataNavigation[$zone]; + $navigationZoneElement = $this->findWithWait(".ez-zone[data-navigation='$dataNavigationValue']"); + $navigationZoneElement->click(); $this->waitWhileLoading(); // Clicking navigation zone triggers load of first item, // we must wait before interacting with the page (see EZP-25128) @@ -170,18 +181,6 @@ public function clickNavigationZone($zone) $this->sleep(); } - /** - * @Given I click on the :button button number :index - * Click on a PlatformUI button - * - * @param string $button Text of the element to click - * @param string $index WHAT IS THIS?! - */ - public function clickButtonWithIndex($button, $index) - { - $this->clickElementByText($button, 'button', $index); - } - /** * @Given I click (on) the navigation item :item * Click on a PlatformUI sub-menu option @@ -190,7 +189,24 @@ public function clickButtonWithIndex($button, $index) */ public function clickNavigationItem($item) { - $this->clickElementByText($item, '.ez-navigation-item'); + $dataNavigationIdentifier = [ + 'Content structure' => 'content-structure', + 'Media library' => 'media-library', + 'Administration dashboard' => 'admin-dashboard', + 'System information' => 'admin-systeminfo', + 'Sections' => 'admin-sections', + 'Content types' => 'admin-contenttypes', + 'Languages' => 'admin-languages', + 'Users' => 'admin-users', + 'Roles' => 'admin-roles', + + ]; + + $item = $dataNavigationIdentifier[$item]; + $navigationZoneElement = $this->findWithWait( + ".ez-view-navigationitemview[data-navigation-item-identifier='$item'] .ez-navigation-item" + ); + $navigationZoneElement->click(); $this->waitWhileLoading(); } @@ -202,7 +218,16 @@ public function clickNavigationItem($item) */ public function clickDiscoveryBar($button) { - $this->clickElementByText($button, '.ez-view-discoverybarview .ez-action', '.action-label'); + $dataAction = [ + 'Minimize' => 'minimizeDiscoveryBar', + 'Content tree' => 'tree', + 'Trash' => 'viewTrash', + ]; + // @TODO throw exception if missing dataAction + $button = $dataAction[$button]; + $buttonElement = $this->findWithWait(".ez-view-discoverybarview .ez-action[data-action='$button']"); + $this->waitWhileLoading(); + $buttonElement->click(); $this->waitWhileLoading(); } @@ -214,7 +239,18 @@ public function clickDiscoveryBar($button) */ public function clickActionBar($button) { - $this->clickElementByText($button, '.ez-actionbar-container .ez-action', '.action-label'); + $dataAction = [ + 'Minimize' => 'minimizeActionBar', + 'Create' => 'createContent', + 'Edit' => 'edit', + 'Move' => 'move', + 'Copy' => 'copy', + 'Send to Trash' => 'sendToTrash', + ]; + // @TODO throw exception if missing dataAction + $button = $dataAction[$button]; + $buttonElement = $this->findWithWait(".ez-actionbar-container .ez-action[data-action='$button']"); + $buttonElement->click(); $this->waitWhileLoading(); } @@ -226,7 +262,15 @@ public function clickActionBar($button) */ public function clickEditActionBar($button) { - $this->clickElementByText($button, '.ez-editactionbar-container .ez-action', '.action-label'); + $dataAction = [ + 'Publish' => 'publish', + 'Save' => 'save', + 'Discard changes' => 'discard', + ]; + // @TODO throw exception if missing dataAction + $button = $dataAction[$button]; + $buttonElement = $this->findWithWait(".ez-editactionbar-container .ez-action[data-action='$button']"); + $buttonElement->click(); $this->waitWhileLoading(); } @@ -242,6 +286,7 @@ public function clickOnTreePath($path) $node = $this->findWithWait('.ez-view-discoverybarview'); $this->clickDiscoveryBar('Content tree'); $this->openTreePath($path, $node); + $this->waitWhileLoading(); } /** @@ -252,7 +297,11 @@ public function clickOnTreePath($path) */ public function clickContentType($contentType) { - $this->clickElementByText($contentType, '.ez-contenttypeselector-types .ez-selection-filter-item '); + $contentTypeElement = $this->findWithWait( + ".ez-contenttypeselector-types .ez-selection-filter-item[data-text='$contentType']" + ); + $contentTypeElement->click(); + //$this->clickElementByText($contentType, '.ez-contenttypeselector-types .ez-selection-filter-item'); $this->waitWhileLoading(); } @@ -291,7 +340,8 @@ public function selectFromUniversalDiscovery($path) */ public function confirmSelection() { - $this->clickElementByText('Confirm selection', '.ez-universaldiscovery-confirm'); + $confirmElement = $this->findWithWait('.ez-universaldiscovery-confirm'); + $confirmElement->click(); } /** @@ -394,6 +444,7 @@ public function iSeeElements(TableNode $elements) $found = false; $name = array_values($element)[0]; $found = $this->getElementByText($name, '.ez-selection-filter-item'); + // @TODO implement without get by text Assertion::assertNotNull($found, "Element: $name not found"); } } @@ -418,8 +469,7 @@ public function iSeeElementFile($element, $file) */ public function iShouldBeOnTheDashboard() { - $this->waitWhileLoading(); - $this->findWithWait('.ez-dashboard-content'); + $this->assertSession()->elementExists('css', '.ez-view-dashboardblocksview'); } /** From 5fced360fbafd1570f2bc751057a66d08495fb54 Mon Sep 17 00:00:00 2001 From: Miguel Jacinto Date: Tue, 11 Oct 2016 15:03:06 +0100 Subject: [PATCH 2/5] [Behat] Improve logout link css selector --- Features/Context/SubContext/Authentication.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Features/Context/SubContext/Authentication.php b/Features/Context/SubContext/Authentication.php index d90712a14..b8c9e3d93 100644 --- a/Features/Context/SubContext/Authentication.php +++ b/Features/Context/SubContext/Authentication.php @@ -35,8 +35,7 @@ public function goToPlatformUiAndLogIn($username, $password) $this->waitWhileLoading(); $this->fillFieldWithValue('username', $username); $this->fillFieldWithValue('password', $password); - $loginButton = $this->findWithWait('.ez-loginform-button'); - $loginButton->click(); + $this->findWithWait('.ez-loginform-button')->click(); $this->iShouldBeLoggedIn(); $this->shouldBeLoggedIn = true; } @@ -70,7 +69,9 @@ public function iLogout() $this->waitWhileLoading(); $el->click(); $this->waitWhileLoading(); - $this->iClickAtLink('Logout'); + $this + ->findWithWait('.ez-view-usermenuitemfireeventview[data-event-name="logOut"] .ez-user-menu-item') + ->click(); } /** From cf27ad11d7b23dd044aa763f04a0dbf9db387932 Mon Sep 17 00:00:00 2001 From: Miguel Jacinto Date: Mon, 25 Jul 2016 15:52:47 +0100 Subject: [PATCH 3/5] [Behat] Add missing exceptions to CommonAction context --- Features/Context/SubContext/CommonActions.php | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/Features/Context/SubContext/CommonActions.php b/Features/Context/SubContext/CommonActions.php index 0329bd94a..742a21f03 100644 --- a/Features/Context/SubContext/CommonActions.php +++ b/Features/Context/SubContext/CommonActions.php @@ -10,6 +10,7 @@ namespace EzSystems\PlatformUIBundle\Features\Context\SubContext; use EzSystems\BehatBundle\Helper\EzAssertion; +use Exception; trait CommonActions { @@ -49,7 +50,7 @@ public function fillFieldWithValue($field, $value = '') function () use ($field) { $fieldNode = $this->getSession()->getPage()->findField($field); if ($fieldNode == null) { - throw new \Exception('Field not found'); + throw new Exception('Field not found'); } return $fieldNode; @@ -72,7 +73,7 @@ function () use ($fieldNode, $field, $value) { $this->sleep(); $check = $this->getSession()->getPage()->findField($field)->getValue(); if ($check != $value) { - throw new \Exception('Failed to set the field value: ' . $check); + throw new Exception('Failed to set the field value: ' . $check); } return true; @@ -95,7 +96,7 @@ function () use ($title, $page) { return $titleElement; } } - throw new \Exception("Title '$title' not found"); + throw new Exception("Title '$title' not found"); } ); } @@ -107,7 +108,7 @@ public function seeInputField($label) { $field = $this->getSession()->getPage()->findField($label); if (!$field) { - throw new \Exception("Field '$label' not found"); + throw new Exception("Field '$label' not found"); } } @@ -171,6 +172,11 @@ public function clickNavigationZone($zone) 'Performance' => 'studioplus', 'Admin Panel' => 'admin', ]; + + if (!isset($dataNavigation[$zone])) { + throw new Exception("Navigation zone $zone does not exist"); + } + $dataNavigationValue = $dataNavigation[$zone]; $navigationZoneElement = $this->findWithWait(".ez-zone[data-navigation='$dataNavigationValue']"); $navigationZoneElement->click(); @@ -223,7 +229,11 @@ public function clickDiscoveryBar($button) 'Content tree' => 'tree', 'Trash' => 'viewTrash', ]; - // @TODO throw exception if missing dataAction + + if (!isset($dataAction[$button])) { + throw new Exception("Discovery bar button $button does not exist"); + } + $button = $dataAction[$button]; $buttonElement = $this->findWithWait(".ez-view-discoverybarview .ez-action[data-action='$button']"); $this->waitWhileLoading(); @@ -247,7 +257,11 @@ public function clickActionBar($button) 'Copy' => 'copy', 'Send to Trash' => 'sendToTrash', ]; - // @TODO throw exception if missing dataAction + + if (!isset($dataAction[$button])) { + throw new Exception("Action bar button $button does not exist"); + } + $button = $dataAction[$button]; $buttonElement = $this->findWithWait(".ez-actionbar-container .ez-action[data-action='$button']"); $buttonElement->click(); @@ -267,7 +281,11 @@ public function clickEditActionBar($button) 'Save' => 'save', 'Discard changes' => 'discard', ]; - // @TODO throw exception if missing dataAction + + if (!isset($dataAction[$button])) { + throw new Exception("Edit Action bar button $button does not exist"); + } + $button = $dataAction[$button]; $buttonElement = $this->findWithWait(".ez-editactionbar-container .ez-action[data-action='$button']"); $buttonElement->click(); @@ -386,12 +404,12 @@ public function dontSeeTreePath($path) $found = true; try { $this->clickOnTreePath($path); - } catch (\Exception $e) { + } catch (Exception $e) { $found = false; } if ($found) { - throw new \Exception("Tree path '$path' was found"); + throw new Exception("Tree path '$path' was found"); } return true; @@ -415,10 +433,10 @@ public function contentExists($contentName, $contentType) */ public function iSeeNotification($message) { - $this->sleep(); - $result = $this->getElementByText($message, '.ez-notification-text'); + // @TODO check notification content + $result = $this->findWithWait('.ez-notification-text'); if (!$result) { - throw new \Exception("The notification with message '$message' was not shown"); + throw new Exception("The notification with message '$message' was not shown"); } } @@ -429,10 +447,10 @@ public function iDoNotSeeNotification($message) { try { $this->iSeeNotification($message); - } catch (\Exception $e) { + } catch (Exception $e) { return; } - throw new \Exception("Unexpected notification shown with message '$message'"); + throw new Exception("Unexpected notification shown with message '$message'"); } /** From 71ced7788d86bd19d5ed464aa21831b586abaff9 Mon Sep 17 00:00:00 2001 From: Miguel Jacinto Date: Mon, 25 Jul 2016 15:31:19 +0100 Subject: [PATCH 4/5] [Behat] Removed unnused methods --- Features/Context/SubContext/CommonActions.php | 68 ------------------- 1 file changed, 68 deletions(-) diff --git a/Features/Context/SubContext/CommonActions.php b/Features/Context/SubContext/CommonActions.php index 742a21f03..7326c6d69 100644 --- a/Features/Context/SubContext/CommonActions.php +++ b/Features/Context/SubContext/CommonActions.php @@ -14,30 +14,6 @@ trait CommonActions { - /** - * @Given I clicked on/at (the) :link link - * @When I click on/at (the) :link link - * - * Click a link with text ':link' - */ - public function iClickAtLink($link) - { - $this->clickElementByText($link, 'a'); - // @TODO implement click on link without get by text - } - - /** - * @Given I clicked on/at (the) :button button - * @When I click on/at (the) :button button - * - * Clicks the button identified by ':button' - */ - public function iClickAtButton($button) - { - $this->clickElementByText($button, 'button'); - // @TODO implement click on link without get by text - } - /** * @When I fill in :field with :value * @When I set :field as empty @@ -146,18 +122,6 @@ public function clickLogo() $page->find('css', $selector)->click(); } - /** - * @Given I click (on) the tab :tab - * Clicks on a PlatformUI tab - * - * @param string $tab Text of the element to click - */ - public function clickTab($tab) - { - $this->clickElementByText($tab, '.ez-tabs-label a[href]'); - // @TODO implement without get by text - } - /** * @Given I click (on) the navigation zone :zone * Click on a PlatformUI menu zone @@ -319,27 +283,9 @@ public function clickContentType($contentType) ".ez-contenttypeselector-types .ez-selection-filter-item[data-text='$contentType']" ); $contentTypeElement->click(); - //$this->clickElementByText($contentType, '.ez-contenttypeselector-types .ez-selection-filter-item'); $this->waitWhileLoading(); } - /** - * @Given I create a content of content type :type with: - */ - public function iCreateContentType($type, TableNode $fields) - { - $this->clickNavigationZone('Platform'); - $this->iClickAtLink('Content structure'); - $this->clickActionBar('Create a content'); - $this->clickContentType($type); - foreach ($fields as $fieldArray) { - $keys = array_keys($fieldArray); - for ($i = 0; $i < count($keys); ++$i) { - $this->fillFieldWithValue($keys[$i], $fieldArray[$keys[$i]]); - } - } - } - /** * @When I select the :path folder in the Universal Discovery Widget */ @@ -453,20 +399,6 @@ public function iDoNotSeeNotification($message) throw new Exception("Unexpected notification shown with message '$message'"); } - /** - * @Then I should see elements with the following names: - */ - public function iSeeElements(TableNode $elements) - { - foreach ($elements as $element) { - $found = false; - $name = array_values($element)[0]; - $found = $this->getElementByText($name, '.ez-selection-filter-item'); - // @TODO implement without get by text - Assertion::assertNotNull($found, "Element: $name not found"); - } - } - /** * @Then I should see (an) element :element with (an) file :file */ From da10b7a8cc5775fd5eafe08e018c9227531ca165 Mon Sep 17 00:00:00 2001 From: Miguel Jacinto Date: Wed, 26 Oct 2016 14:07:43 +0100 Subject: [PATCH 5/5] [Behat] Use node id to select elements from content tree --- Features/Context/PlatformUI.php | 101 +++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 21 deletions(-) diff --git a/Features/Context/PlatformUI.php b/Features/Context/PlatformUI.php index 23d3f0601..721370412 100644 --- a/Features/Context/PlatformUI.php +++ b/Features/Context/PlatformUI.php @@ -10,6 +10,10 @@ namespace EzSystems\PlatformUIBundle\Features\Context; use EzSystems\BehatBundle\Context\Browser\Context; +use eZ\Publish\API\Repository\SearchService; +use eZ\Publish\API\Repository\Values\Content\LocationQuery; +use eZ\Publish\API\Repository\Values\Content\Query\Criterion; +use eZ\Publish\Core\Persistence\Legacy\Exception\TypeNotFound as TypeNotFoundException; class PlatformUI extends Context { @@ -17,6 +21,14 @@ class PlatformUI extends Context * Default Platform URI. */ const PLATFORM_URI = 'ez'; + /** + * Default Platform URI admin username. + */ + const PLATFORM_USERNAME = 'admin'; + /** + * Default Platform admin user password. + */ + const PLATFORM_USERPASSWORD = 'publish'; /** * Max. time to wait while loading elements (f.e. during rest calls). @@ -60,18 +72,18 @@ class PlatformUI extends Context protected $lastException; /** - * User account name, admin by default. + * User account name. * * @var string */ - protected $user = 'admin'; + protected $user; /** - * User account password, publish by default. + * User account password. * * @var string */ - protected $password = 'publish'; + protected $password; /** * Stores the status of the platform. @@ -84,23 +96,25 @@ class PlatformUI extends Context */ protected $newPathsMap = array(); + /** + * Ezpublish api Search service. + */ + protected $searchService; + /** * Initialize class. * - * @param string $uri + * @injectService $searchService @ezpublish.api.service.search */ - public function __construct($uri = self::PLATFORM_URI, $user = null, $password = null) + public function __construct($searchService) { parent::__construct(); + $this->platformUiUri = self::PLATFORM_URI; + $this->user = self::PLATFORM_USERNAME; + $this->password = self::PLATFORM_USERPASSWORD; + $this->searchService = $searchService; $this->pageIdentifierMap['roles'] = '/ez#/admin/pjax%2Frole'; $this->pageIdentifierMap['users'] = '/ez#/view/%2Fapi%2Fezp%2Fv2%2Fcontent%2Flocations%2F1%2F5/eng-GB'; - $this->platformUiUri = $uri; - if ($user != null) { - $this->user = $user; - } - if ($password != null) { - $this->password = $password; - } } /** @@ -134,13 +148,6 @@ public function beforeStep() $this->waitWhileLoading(); } - /** - * @AfterStep - */ - public function afterStep() - { - } - /** * Setter for the new path of the content name. */ @@ -331,6 +338,57 @@ protected function clickElementByText($text, $selector, $textSelector = null, $b } } + /** + * Returns the path string of the content with the given name. + * + * @param string $contentName + * + * @return string + */ + protected function getContentLocationPath($contentName) + { + $criterion = new Criterion\ContentTypeIdentifier($contentName); + $query = new LocationQuery( + array( + 'query' => $criterion, + ) + ); + + $searchResult = null; + try { + $searchResult = $this->searchService->findLocations($query); + } catch (TypeNotFoundException $e) { + // do nothing if the content type identifier does not exist + } + + if (!$searchResult) { + $criterions = array( + new Criterion\Field('title', Criterion\Operator::EQ, $contentName), + new Criterion\Field('short_title', Criterion\Operator::EQ, $contentName), + new Criterion\Field('name', Criterion\Operator::EQ, $contentName), + new Criterion\Field('short_name', Criterion\Operator::EQ, $contentName), + ); + $query = new LocationQuery( + array( + 'query' => new Criterion\LogicalOr($criterions), + ) + ); + $searchResult = $this->searchService->findLocations($query); + } + + $pathString = null; + foreach ($searchResult->searchHits as $searchHit) { + $pathString = $searchHit->valueObject->pathString; + } + + if (!$pathString) { + throw new \Exception("Content $contentName not found"); + } + $pathString = rtrim($pathString, '/'); + + return $pathString; + } + /** * Opens a content tree node based on the root of the tree or a given node. * @@ -355,8 +413,9 @@ protected function openTreeNode($text, $parentNode) ); } } + $nodeId = '/api/ezp/v2/content/locations' . $this->getContentLocationPath($text); // find an '.ez-tree-node' element which contains an '.ez-tree-navigate' with text '$text' - $element = $this->getElementByText($text, '.ez-tree-node', '.ez-tree-navigate', $parentNode); + $element = $this->findWithWait(".ez-tree-node[data-node-id='$nodeId']", $parentNode); if (!$element) { throw new \Exception("The tree node '$text' was not found"); }