Skip to content

Commit e175381

Browse files
authored
Merge pull request #343 from netresearch/CLI-direct-shell-exec
Allow the webdriver to directly call upon the 'bin/magento' executable
2 parents f110875 + bdd0735 commit e175381

File tree

1 file changed

+103
-41
lines changed

1 file changed

+103
-41
lines changed

src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php

Lines changed: 103 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616
use Codeception\Util\Uri;
1717
use Magento\FunctionalTestingFramework\DataGenerator\Handlers\CredentialStore;
1818
use Magento\FunctionalTestingFramework\DataGenerator\Persist\Curl\WebapiExecutor;
19-
use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport;
2019
use Magento\FunctionalTestingFramework\Util\Protocol\CurlInterface;
2120
use Magento\FunctionalTestingFramework\Util\ConfigSanitizerUtil;
2221
use Yandex\Allure\Adapter\AllureException;
22+
use Magento\FunctionalTestingFramework\Util\Protocol\CurlTransport;
23+
use Symfony\Component\Process\Process;
2324
use Yandex\Allure\Adapter\Support\AttachmentSupport;
2425
use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException;
2526

@@ -49,14 +50,15 @@ class MagentoWebDriver extends WebDriver
4950

5051
/**
5152
* List of known magento loading masks by selector
53+
*
5254
* @var array
5355
*/
5456
public static $loadingMasksLocators = [
5557
'//div[contains(@class, "loading-mask")]',
5658
'//div[contains(@class, "admin_data-grid-loading-mask")]',
5759
'//div[contains(@class, "admin__data-grid-loading-mask")]',
5860
'//div[contains(@class, "admin__form-loading-mask")]',
59-
'//div[@data-role="spinner"]'
61+
'//div[@data-role="spinner"]',
6062
];
6163

6264
/**
@@ -69,7 +71,7 @@ class MagentoWebDriver extends WebDriver
6971
'backend_name',
7072
'username',
7173
'password',
72-
'browser'
74+
'browser',
7375
];
7476

7577
/**
@@ -116,6 +118,7 @@ class MagentoWebDriver extends WebDriver
116118

117119
/**
118120
* Sanitizes config, then initializes using parent.
121+
*
119122
* @return void
120123
*/
121124
public function _initialize()
@@ -139,6 +142,7 @@ public function _resetConfig()
139142

140143
/**
141144
* Remap parent::_after, called in TestContextExtension
145+
*
142146
* @param TestInterface $test
143147
* @return void
144148
*/
@@ -149,9 +153,10 @@ public function _runAfter(TestInterface $test)
149153

150154
/**
151155
* Override parent::_after to do nothing.
152-
* @return void
156+
*
153157
* @param TestInterface $test
154158
* @SuppressWarnings(PHPMD)
159+
* @return void
155160
*/
156161
public function _after(TestInterface $test)
157162
{
@@ -161,9 +166,9 @@ public function _after(TestInterface $test)
161166
/**
162167
* Returns URL of a host.
163168
*
164-
* @api
165169
* @return mixed
166170
* @throws ModuleConfigException
171+
* @api
167172
*/
168173
public function _getUrl()
169174
{
@@ -173,22 +178,24 @@ public function _getUrl()
173178
"Module connection failure. The URL for client can't bre retrieved"
174179
);
175180
}
181+
176182
return $this->config['url'];
177183
}
178184

179185
/**
180186
* Uri of currently opened page.
181187
*
182188
* @return string
183-
* @api
184189
* @throws ModuleException
190+
* @api
185191
*/
186192
public function _getCurrentUri()
187193
{
188194
$url = $this->webDriver->getCurrentURL();
189195
if ($url == 'about:blank') {
190196
throw new ModuleException($this, 'Current url is blank, no page was opened');
191197
}
198+
192199
return Uri::retrieveUri($url);
193200
}
194201

@@ -257,6 +264,7 @@ public function grabFromCurrentUrl($regex = null)
257264
if (!isset($matches[1])) {
258265
$this->fail("Nothing to grab. A regex parameter with a capture group is required. Ex: '/(foo)(bar)/'");
259266
}
267+
260268
return $matches[1];
261269
}
262270

@@ -326,13 +334,13 @@ public function closeAdminNotification()
326334
* @param string $select
327335
* @param array $options
328336
* @param boolean $requireAction
329-
* @throws \Exception
330337
* @return void
338+
* @throws \Exception
331339
*/
332340
public function searchAndMultiSelectOption($select, array $options, $requireAction = false)
333341
{
334-
$selectDropdown = $select . ' .action-select.admin__action-multiselect';
335-
$selectSearchText = $select
342+
$selectDropdown = $select . ' .action-select.admin__action-multiselect';
343+
$selectSearchText = $select
336344
. ' .admin__action-multiselect-search-wrap>input[data-role="advanced-select-text"]';
337345
$selectSearchResult = $select . ' .admin__action-multiselect-label>span';
338346

@@ -355,8 +363,8 @@ public function searchAndMultiSelectOption($select, array $options, $requireActi
355363
* @param string $selectSearchTextField
356364
* @param string $selectSearchResult
357365
* @param string[] $options
358-
* @throws \Exception
359366
* @return void
367+
* @throws \Exception
360368
*/
361369
public function selectMultipleOptions($selectSearchTextField, $selectSearchResult, array $options)
362370
{
@@ -393,8 +401,8 @@ public function waitForAjaxLoad($timeout = null)
393401
* Wait for all JavaScript to finish executing.
394402
*
395403
* @param integer $timeout
396-
* @throws \Exception
397404
* @return void
405+
* @throws \Exception
398406
*/
399407
public function waitForPageLoad($timeout = null)
400408
{
@@ -409,8 +417,8 @@ public function waitForPageLoad($timeout = null)
409417
* Wait for all visible loading masks to disappear. Gets all elements by mask selector, then loops over them.
410418
*
411419
* @param integer $timeout
412-
* @throws \Exception
413420
* @return void
421+
* @throws \Exception
414422
*/
415423
public function waitForLoadingMaskToDisappear($timeout = null)
416424
{
@@ -438,6 +446,7 @@ public function formatMoney(float $money, $locale = 'en_US.UTF-8')
438446
$this->mResetLocale();
439447
$prefix = substr($money, 0, 1);
440448
$number = substr($money, 1);
449+
441450
return ['prefix' => $prefix, 'number' => $number];
442451
}
443452

@@ -450,6 +459,7 @@ public function formatMoney(float $money, $locale = 'en_US.UTF-8')
450459
public function parseFloat($floatString)
451460
{
452461
$floatString = str_replace(',', '', $floatString);
462+
453463
return floatval($floatString);
454464
}
455465

@@ -471,6 +481,7 @@ public function mSetLocale(int $category, $locale)
471481

472482
/**
473483
* Reset Locale setting.
484+
*
474485
* @return void
475486
*/
476487
public function mResetLocale()
@@ -485,6 +496,7 @@ public function mResetLocale()
485496

486497
/**
487498
* Scroll to the Top of the Page.
499+
*
488500
* @return void
489501
*/
490502
public function scrollToTopOfPage()
@@ -493,51 +505,36 @@ public function scrollToTopOfPage()
493505
}
494506

495507
/**
496-
* Takes given $command and executes it against exposed MTF CLI entry point. Returns response from server.
508+
* Takes given $command and executes it against bin/magento or custom exposed entrypoint. Returns command output.
509+
*
497510
* @param string $command
498511
* @param string $arguments
499-
* @throws TestFrameworkException
500512
* @return string
513+
* @throws TestFrameworkException
501514
*/
502515
public function magentoCLI($command, $arguments = null)
503516
{
504-
// Remove index.php if it's present in url
505-
$baseUrl = rtrim(
506-
str_replace('index.php', '', rtrim($this->config['url'], '/')),
507-
'/'
508-
);
509-
$apiURL = $baseUrl . '/' . ltrim(getenv('MAGENTO_CLI_COMMAND_PATH'), '/');
510-
511-
$restExecutor = new WebapiExecutor();
512-
$executor = new CurlTransport();
513-
$executor->write(
514-
$apiURL,
515-
[
516-
'token' => $restExecutor->getAuthToken(),
517-
getenv('MAGENTO_CLI_COMMAND_PARAMETER') => $command,
518-
'arguments' => $arguments
519-
],
520-
CurlInterface::POST,
521-
[]
522-
);
523-
$response = $executor->read();
524-
$restExecutor->close();
525-
$executor->close();
526-
return $response;
517+
try {
518+
return $this->shellExecMagentoCLI($command, $arguments);
519+
} catch (\Exception $exception) {
520+
return $this->curlExecMagentoCLI($command, $arguments);
521+
}
527522
}
528523

529524
/**
530525
* Runs DELETE request to delete a Magento entity against the url given.
526+
*
531527
* @param string $url
532-
* @throws TestFrameworkException
533528
* @return string
529+
* @throws TestFrameworkException
534530
*/
535531
public function deleteEntityByUrl($url)
536532
{
537533
$executor = new WebapiExecutor(null);
538534
$executor->write($url, [], CurlInterface::DELETE, []);
539535
$response = $executor->read();
540536
$executor->close();
537+
541538
return $response;
542539
}
543540

@@ -547,8 +544,8 @@ public function deleteEntityByUrl($url)
547544
* @param string $selector
548545
* @param string $dependentSelector
549546
* @param boolean $visible
550-
* @throws \Exception
551547
* @return void
548+
* @throws \Exception
552549
*/
553550
public function conditionalClick($selector, $dependentSelector, $visible)
554551
{
@@ -603,6 +600,7 @@ public function assertElementContainsAttribute($selector, $attribute, $value)
603600

604601
/**
605602
* Sets current test to the given test, and resets test failure artifacts to null
603+
*
606604
* @param TestInterface $test
607605
* @return void
608606
*/
@@ -617,6 +615,7 @@ public function _before(TestInterface $test)
617615

618616
/**
619617
* Override for codeception's default dragAndDrop to include offset options.
618+
*
620619
* @param string $source
621620
* @param string $target
622621
* @param integer $xOffset
@@ -711,6 +710,7 @@ public function _failed(TestInterface $test, $fail)
711710

712711
/**
713712
* Function which saves a screenshot of the current stat of the browser
713+
*
714714
* @return void
715715
*/
716716
public function saveScreenshot()
@@ -730,8 +730,8 @@ public function saveScreenshot()
730730
* Go to a page and wait for ajax requests to finish
731731
*
732732
* @param string $page
733-
* @throws \Exception
734733
* @return void
734+
* @throws \Exception
735735
*/
736736
public function amOnPage($page)
737737
{
@@ -743,8 +743,8 @@ public function amOnPage($page)
743743
* Turn Readiness check on or off
744744
*
745745
* @param boolean $check
746-
* @throws \Exception
747746
* @return void
747+
* @throws \Exception
748748
*/
749749
public function skipReadinessCheck($check)
750750
{
@@ -787,6 +787,7 @@ private function getJsErrors()
787787
$errors .= "\n" . $jsError;
788788
}
789789
}
790+
790791
return $errors;
791792
}
792793

@@ -824,4 +825,65 @@ public function makeScreenshot($name = null)
824825
$this->debug("Screenshot saved to $screenName");
825826
AllureHelper::addAttachmentToCurrentStep($screenName, 'Screenshot');
826827
}
828+
829+
/**
830+
* Takes given $command and executes it against bin/magento executable. Returns stdout output from the command.
831+
*
832+
* @param string $command
833+
* @param string $arguments
834+
*
835+
* @throws \RuntimeException
836+
* @return string
837+
*/
838+
private function shellExecMagentoCLI($command, $arguments): string
839+
{
840+
$php = PHP_BINDIR ? PHP_BINDIR . DIRECTORY_SEPARATOR. 'php' : 'php';
841+
$binMagento = realpath(MAGENTO_BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento');
842+
$command = $php . ' -f ' . $binMagento . ' ' . $command . ' ' . $arguments;
843+
$process = new Process(escapeshellcmd($command), MAGENTO_BP);
844+
$process->setIdleTimeout(60);
845+
$process->setTimeout(0);
846+
$exitCode = $process->run();
847+
if ($exitCode !== 0) {
848+
throw new \RuntimeException($process->getErrorOutput());
849+
}
850+
851+
return $process->getOutput();
852+
}
853+
854+
/**
855+
* Takes given $command and executes it against exposed MTF CLI entry point. Returns response from server.
856+
*
857+
* @param string $command
858+
* @param string $arguments
859+
* @return string
860+
* @throws TestFrameworkException
861+
*/
862+
private function curlExecMagentoCLI($command, $arguments): string
863+
{
864+
// Remove index.php if it's present in url
865+
$baseUrl = rtrim(
866+
str_replace('index.php', '', rtrim($this->config['url'], '/')),
867+
'/'
868+
);
869+
$apiURL = $baseUrl . '/' . ltrim(getenv('MAGENTO_CLI_COMMAND_PATH'), '/');
870+
871+
$restExecutor = new WebapiExecutor();
872+
$executor = new CurlTransport();
873+
$executor->write(
874+
$apiURL,
875+
[
876+
'token' => $restExecutor->getAuthToken(),
877+
getenv('MAGENTO_CLI_COMMAND_PARAMETER') => $command,
878+
'arguments' => $arguments,
879+
],
880+
CurlInterface::POST,
881+
[]
882+
);
883+
$response = $executor->read();
884+
$restExecutor->close();
885+
$executor->close();
886+
887+
return $response;
888+
}
827889
}

0 commit comments

Comments
 (0)