From 90320b179ee6a64249c1e830e9f40d9c29304d06 Mon Sep 17 00:00:00 2001 From: Paul Siedler Date: Thu, 25 Apr 2019 15:16:40 +0200 Subject: [PATCH 1/2] #339: allow direct execution of the bin/magento executable instead of calling custom endpoint --- .../Module/MagentoWebDriver.php | 178 ++++++++++++------ 1 file changed, 120 insertions(+), 58 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 93e6a5968..91c00c691 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -6,20 +6,21 @@ namespace Magento\FunctionalTestingFramework\Module; +use Codeception\Exception\ModuleConfigException; +use Codeception\Exception\ModuleException; use Codeception\Module\WebDriver; use Codeception\Test\Descriptor; use Codeception\TestInterface; -use Facebook\WebDriver\Interactions\WebDriverActions; -use Codeception\Exception\ModuleConfigException; -use Codeception\Exception\ModuleException; use Codeception\Util\Uri; +use Facebook\WebDriver\Interactions\WebDriverActions; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore; use Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl\WebapiExecutor; -use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport; -use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Util\ConfigSanitizerUtil; +use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface; +use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport; +use Symfony\Component\Process\Process; use Yandex\Allure\Adapter\Support\AttachmentSupport; -use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; /** * MagentoWebDriver module provides common Magento web actions through Selenium WebDriver. @@ -47,6 +48,7 @@ class MagentoWebDriver extends WebDriver /** * List of known magento loading masks by selector + * * @var array */ public static $loadingMasksLocators = [ @@ -54,7 +56,7 @@ class MagentoWebDriver extends WebDriver '//div[contains(@class, "admin_data-grid-loading-mask")]', '//div[contains(@class, "admin__data-grid-loading-mask")]', '//div[contains(@class, "admin__form-loading-mask")]', - '//div[@data-role="spinner"]' + '//div[@data-role="spinner"]', ]; /** @@ -67,7 +69,7 @@ class MagentoWebDriver extends WebDriver 'backend_name', 'username', 'password', - 'browser' + 'browser', ]; /** @@ -114,6 +116,7 @@ class MagentoWebDriver extends WebDriver /** * Sanitizes config, then initializes using parent. + * * @return void */ public function _initialize() @@ -137,6 +140,7 @@ public function _resetConfig() /** * Remap parent::_after, called in TestContextExtension + * * @param TestInterface $test * @return void */ @@ -147,9 +151,10 @@ public function _runAfter(TestInterface $test) /** * Override parent::_after to do nothing. - * @return void + * * @param TestInterface $test * @SuppressWarnings(PHPMD) + * @return void */ public function _after(TestInterface $test) { @@ -159,9 +164,9 @@ public function _after(TestInterface $test) /** * Returns URL of a host. * - * @api * @return mixed * @throws ModuleConfigException + * @api */ public function _getUrl() { @@ -171,6 +176,7 @@ public function _getUrl() "Module connection failure. The URL for client can't bre retrieved" ); } + return $this->config['url']; } @@ -178,8 +184,8 @@ public function _getUrl() * Uri of currently opened page. * * @return string - * @api * @throws ModuleException + * @api */ public function _getCurrentUri() { @@ -187,6 +193,7 @@ public function _getCurrentUri() if ($url == 'about:blank') { throw new ModuleException($this, 'Current url is blank, no page was opened'); } + return Uri::retrieveUri($url); } @@ -243,6 +250,7 @@ public function grabFromCurrentUrl($regex = null) if (!isset($matches[1])) { $this->fail("Nothing to grab. A regex parameter with a capture group is required. Ex: '/(foo)(bar)/'"); } + return $matches[1]; } @@ -297,17 +305,17 @@ public function closeAdminNotification() * Search for and Select multiple options from a Magento Multi-Select drop down menu. * e.g. The drop down menu you use to assign Products to Categories. * - * @param string $select - * @param array $options + * @param string $select + * @param array $options * @param boolean $requireAction - * @throws \Exception * @return void + * @throws \Exception */ public function searchAndMultiSelectOption($select, array $options, $requireAction = false) { - $selectDropdown = $select . ' .action-select.admin__action-multiselect'; - $selectSearchText = $select - . ' .admin__action-multiselect-search-wrap>input[data-role="advanced-select-text"]'; + $selectDropdown = $select . ' .action-select.admin__action-multiselect'; + $selectSearchText = $select + . ' .admin__action-multiselect-search-wrap>input[data-role="advanced-select-text"]'; $selectSearchResult = $select . ' .admin__action-multiselect-label>span'; $this->waitForPageLoad(); @@ -326,11 +334,11 @@ public function searchAndMultiSelectOption($select, array $options, $requireActi /** * Select multiple options from a drop down using a filter and text field to narrow results. * - * @param string $selectSearchTextField - * @param string $selectSearchResult + * @param string $selectSearchTextField + * @param string $selectSearchResult * @param string[] $options - * @throws \Exception * @return void + * @throws \Exception */ public function selectMultipleOptions($selectSearchTextField, $selectSearchResult, array $options) { @@ -367,8 +375,8 @@ public function waitForAjaxLoad($timeout = null) * Wait for all JavaScript to finish executing. * * @param integer $timeout - * @throws \Exception * @return void + * @throws \Exception */ public function waitForPageLoad($timeout = null) { @@ -383,8 +391,8 @@ public function waitForPageLoad($timeout = null) * Wait for all visible loading masks to disappear. Gets all elements by mask selector, then loops over them. * * @param integer $timeout - * @throws \Exception * @return void + * @throws \Exception */ public function waitForLoadingMaskToDisappear($timeout = null) { @@ -401,7 +409,7 @@ public function waitForLoadingMaskToDisappear($timeout = null) } /** - * @param float $money + * @param float $money * @param string $locale * @return array */ @@ -412,6 +420,7 @@ public function formatMoney(float $money, $locale = 'en_US.UTF-8') $this->mResetLocale(); $prefix = substr($money, 0, 1); $number = substr($money, 1); + return ['prefix' => $prefix, 'number' => $number]; } @@ -424,12 +433,13 @@ public function formatMoney(float $money, $locale = 'en_US.UTF-8') public function parseFloat($floatString) { $floatString = str_replace(',', '', $floatString); + return floatval($floatString); } /** * @param integer $category - * @param string $locale + * @param string $locale * @return void */ public function mSetLocale(int $category, $locale) @@ -445,6 +455,7 @@ public function mSetLocale(int $category, $locale) /** * Reset Locale setting. + * * @return void */ public function mResetLocale() @@ -459,6 +470,7 @@ public function mResetLocale() /** * Scroll to the Top of the Page. + * * @return void */ public function scrollToTopOfPage() @@ -467,44 +479,28 @@ public function scrollToTopOfPage() } /** - * Takes given $command and executes it against exposed MTF CLI entry point. Returns response from server. + * Takes given $command and executes it against bin/magento or custom exposed entrypoint. Returns command output. + * * @param string $command * @param string $arguments - * @throws TestFrameworkException * @return string + * @throws TestFrameworkException */ public function magentoCLI($command, $arguments = null) { - // Remove index.php if it's present in url - $baseUrl = rtrim( - str_replace('index.php', '', rtrim($this->config['url'], '/')), - '/' - ); - $apiURL = $baseUrl . '/' . ltrim(getenv('MAGENTO_CLI_COMMAND_PATH'), '/'); - - $restExecutor = new WebapiExecutor(); - $executor = new CurlTransport(); - $executor->write( - $apiURL, - [ - 'token' => $restExecutor->getAuthToken(), - getenv('MAGENTO_CLI_COMMAND_PARAMETER') => $command, - 'arguments' => $arguments - ], - CurlInterface::POST, - [] - ); - $response = $executor->read(); - $restExecutor->close(); - $executor->close(); - return $response; + try { + return $this->shellExecMagentoCLI($command, $arguments); + } catch (\Exception $exception) { + return $this->curlExecMagentoCLI($command, $arguments); + } } /** * Runs DELETE request to delete a Magento entity against the url given. + * * @param string $url - * @throws TestFrameworkException * @return string + * @throws TestFrameworkException */ public function deleteEntityByUrl($url) { @@ -512,17 +508,18 @@ public function deleteEntityByUrl($url) $executor->write($url, [], CurlInterface::DELETE, []); $response = $executor->read(); $executor->close(); + return $response; } /** * Conditional click for an area that should be visible * - * @param string $selector - * @param string $dependentSelector + * @param string $selector + * @param string $dependentSelector * @param boolean $visible - * @throws \Exception * @return void + * @throws \Exception */ public function conditionalClick($selector, $dependentSelector, $visible) { @@ -577,6 +574,7 @@ public function assertElementContainsAttribute($selector, $attribute, $value) /** * Sets current test to the given test, and resets test failure artifacts to null + * * @param TestInterface $test * @return void */ @@ -591,8 +589,9 @@ public function _before(TestInterface $test) /** * Override for codeception's default dragAndDrop to include offset options. - * @param string $source - * @param string $target + * + * @param string $source + * @param string $target * @param integer $xOffset * @param integer $yOffset * @return void @@ -641,7 +640,7 @@ public function fillSecretField($field, $value) * following parent execution of test failure processing. * * @param TestInterface $test - * @param \Exception $fail + * @param \Exception $fail * @return void */ public function _failed(TestInterface $test, $fail) @@ -666,6 +665,7 @@ public function _failed(TestInterface $test, $fail) /** * Function which saves a screenshot of the current stat of the browser + * * @return void */ public function saveScreenshot() @@ -685,8 +685,8 @@ public function saveScreenshot() * Go to a page and wait for ajax requests to finish * * @param string $page - * @throws \Exception * @return void + * @throws \Exception */ public function amOnPage($page) { @@ -698,8 +698,8 @@ public function amOnPage($page) * Turn Readiness check on or off * * @param boolean $check - * @throws \Exception * @return void + * @throws \Exception */ public function skipReadinessCheck($check) { @@ -742,6 +742,7 @@ private function getJsErrors() $errors .= "\n" . $jsError; } } + return $errors; } @@ -754,4 +755,65 @@ public function dontSeeJsError() { $this->assertEmpty($this->jsErrors, $this->getJsErrors()); } + + /** + * Takes given $command and executes it against bin/magento executable. Returns stdout output from the command. + * + * @param string $command + * @param string $arguments + * + * @throws \RuntimeException + * @return string + */ + private function shellExecMagentoCLI($command, $arguments): string + { + $php = PHP_BINDIR ? PHP_BINDIR . DIRECTORY_SEPARATOR. 'php' : 'php'; + $binMagento = realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento'); + $command = $php . ' -f ' . $binMagento . ' ' . $command . ' ' . $arguments; + $process = new Process(escapeshellcmd($command), MAGENTO_BP); + $process->setIdleTimeout(60); + $process->setTimeout(0); + $exitCode = $process->run(); + if ($exitCode !== 0) { + throw new \RuntimeException($process->getErrorOutput()); + } + + return $process->getOutput(); + } + + /** + * Takes given $command and executes it against exposed MTF CLI entry point. Returns response from server. + * + * @param string $command + * @param string $arguments + * @return string + * @throws TestFrameworkException + */ + private function curlExecMagentoCLI($command, $arguments): string + { + // Remove index.php if it's present in url + $baseUrl = rtrim( + str_replace('index.php', '', rtrim($this->config['url'], '/')), + '/' + ); + $apiURL = $baseUrl . '/' . ltrim(getenv('MAGENTO_CLI_COMMAND_PATH'), '/'); + + $restExecutor = new WebapiExecutor(); + $executor = new CurlTransport(); + $executor->write( + $apiURL, + [ + 'token' => $restExecutor->getAuthToken(), + getenv('MAGENTO_CLI_COMMAND_PARAMETER') => $command, + 'arguments' => $arguments, + ], + CurlInterface::POST, + [] + ); + $response = $executor->read(); + $restExecutor->close(); + $executor->close(); + + return $response; + } } From f1322810a1698c42fa35dd19b808741615d06f96 Mon Sep 17 00:00:00 2001 From: Paul Siedler Date: Tue, 30 Apr 2019 13:33:08 +0200 Subject: [PATCH 2/2] Fix phpcs issues --- .../Module/MagentoWebDriver.php | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index 91c00c691..1632757a6 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -305,8 +305,8 @@ public function closeAdminNotification() * Search for and Select multiple options from a Magento Multi-Select drop down menu. * e.g. The drop down menu you use to assign Products to Categories. * - * @param string $select - * @param array $options + * @param string $select + * @param array $options * @param boolean $requireAction * @return void * @throws \Exception @@ -334,8 +334,8 @@ public function searchAndMultiSelectOption($select, array $options, $requireActi /** * Select multiple options from a drop down using a filter and text field to narrow results. * - * @param string $selectSearchTextField - * @param string $selectSearchResult + * @param string $selectSearchTextField + * @param string $selectSearchResult * @param string[] $options * @return void * @throws \Exception @@ -409,7 +409,7 @@ public function waitForLoadingMaskToDisappear($timeout = null) } /** - * @param float $money + * @param float $money * @param string $locale * @return array */ @@ -439,7 +439,7 @@ public function parseFloat($floatString) /** * @param integer $category - * @param string $locale + * @param string $locale * @return void */ public function mSetLocale(int $category, $locale) @@ -515,8 +515,8 @@ public function deleteEntityByUrl($url) /** * Conditional click for an area that should be visible * - * @param string $selector - * @param string $dependentSelector + * @param string $selector + * @param string $dependentSelector * @param boolean $visible * @return void * @throws \Exception @@ -590,8 +590,8 @@ public function _before(TestInterface $test) /** * Override for codeception's default dragAndDrop to include offset options. * - * @param string $source - * @param string $target + * @param string $source + * @param string $target * @param integer $xOffset * @param integer $yOffset * @return void @@ -640,7 +640,7 @@ public function fillSecretField($field, $value) * following parent execution of test failure processing. * * @param TestInterface $test - * @param \Exception $fail + * @param \Exception $fail * @return void */ public function _failed(TestInterface $test, $fail)