diff --git a/.travis.yml b/.travis.yml
index fb21686b8..fba3b46ae 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,11 +2,16 @@ language: php
php:
- 7.2
- 7.3
+services:
+ - docker
+before_install:
+ - docker run -d -p 4444:4444 -v /dev/shm:/dev/shm selenium/standalone-chrome:3.141.59-zirconium
install: composer install --no-interaction --prefer-source
env:
matrix:
- VERIFICATION_TOOL=phpunit-checks
- VERIFICATION_TOOL=static-checks
+ - VERIFICATION_TOOL=functional
script:
- bin/$VERIFICATION_TOOL
after_success:
diff --git a/bin/functional b/bin/functional
new file mode 100755
index 000000000..99377337e
--- /dev/null
+++ b/bin/functional
@@ -0,0 +1,10 @@
+# Copyright © Magento, Inc. All rights reserved.
+# See COPYING.txt for license details.
+
+set -e
+
+echo "==============================="
+echo " EXECUTE DevDocsTest "
+echo "==============================="
+bin/mftf build:project
+bin/mftf run:test DevDocsTest -f
diff --git a/composer.json b/composer.json
index 23b0848d5..74743f674 100755
--- a/composer.json
+++ b/composer.json
@@ -53,7 +53,7 @@
"files": ["src/Magento/FunctionalTestingFramework/_bootstrap.php"],
"psr-4": {
"Magento\\FunctionalTestingFramework\\": "src/Magento/FunctionalTestingFramework",
- "MFTF\\": "dev/tests/functional/MFTF"
+ "MFTF\\": "dev/tests/functional/tests/MFTF"
}
},
"autoload-dev": {
diff --git a/composer.lock b/composer.lock
index 43be8f65d..8757833cb 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "ddf9b7965d3a2369bf0f22f5172d75dc",
+ "content-hash": "797f6caab6c9a1ae60da15083d03a548",
"packages": [
{
"name": "allure-framework/allure-codeception",
@@ -6872,7 +6872,8 @@
"php": "~7.2.0||~7.3.0",
"ext-curl": "*",
"ext-json": "*",
- "ext-openssl": "*"
+ "ext-openssl": "*",
+ "ext-dom": "*"
},
"platform-dev": []
}
diff --git a/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/HelperActionGroup.xml b/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/HelperActionGroup.xml
new file mode 100644
index 000000000..4e39a2da1
--- /dev/null
+++ b/dev/tests/functional/tests/MFTF/DevDocs/ActionGroup/HelperActionGroup.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+ {{contentSection.parametrizedSelector(test)}}
+ ['{{test}}', 'Bla']
+ {{test}}
+ true
+ 4.400000000234234
+ 42
+
+
+
diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Data/HelperData.xml b/dev/tests/functional/tests/MFTF/DevDocs/Data/HelperData.xml
new file mode 100644
index 000000000..bc84a5fb2
--- /dev/null
+++ b/dev/tests/functional/tests/MFTF/DevDocs/Data/HelperData.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ Some kind of data for testing purposes
+
+
diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php
new file mode 100644
index 000000000..46fba18d9
--- /dev/null
+++ b/dev/tests/functional/tests/MFTF/DevDocs/Helper/CustomHelper.php
@@ -0,0 +1,49 @@
+ 'value', 'test']
+ ) {
+ print('Hello, this is custom helper which provides an ability to write custom solutions.' . PHP_EOL);
+ print('string $url = ' . $url . PHP_EOL);
+ print('$test = ' . $test . PHP_EOL);
+ print('$bool = ' . $bool . PHP_EOL);
+ print('$int = ' . $int . PHP_EOL);
+ print('$float = ' . $float . PHP_EOL);
+ print('array $module = [' . implode(', ', $module) . ']' . PHP_EOL);
+ print('$superBla = ' . $superBla . PHP_EOL);
+ print('$bla = ' . $bla . PHP_EOL);
+ print('array $arraysomething = [' . implode(', ', $arraysomething) . ']' . PHP_EOL);
+ }
+}
diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml b/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml
index c318fac3f..e0a133d51 100644
--- a/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml
+++ b/dev/tests/functional/tests/MFTF/DevDocs/Section/ContentSection.xml
@@ -10,6 +10,7 @@
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml
index 5944a964c..6aae104ed 100644
--- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml
+++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DeprecatedDevDocsTest.xml
@@ -22,6 +22,6 @@
-
+
diff --git a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml
index 592294889..e7c3bed54 100644
--- a/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml
+++ b/dev/tests/functional/tests/MFTF/DevDocs/Test/DevDocsTest.xml
@@ -22,5 +22,28 @@
+
+ {{contentSection.pageIntro}}
+ ['Test', 'Bla']
+ {{MFTFDocPage.url}}
+ true
+ 1.2
+ 123
+
+
+
+ {{contentSection.pageIntro}}
+ []
+ {{DeprecatedMFTFDocPage.url}}
+ 1.2
+
+ false
+ 4.223
+ 987
+
+
+
+
+
diff --git a/etc/config/functional.suite.dist.yml b/etc/config/functional.suite.dist.yml
index 10fe1212d..ffbb60990 100644
--- a/etc/config/functional.suite.dist.yml
+++ b/etc/config/functional.suite.dist.yml
@@ -12,8 +12,6 @@ namespace: Magento\FunctionalTestingFramework
modules:
enabled:
- \Magento\FunctionalTestingFramework\Module\MagentoWebDriver
- - \Magento\FunctionalTestingFramework\Helper\Acceptance
- - \Magento\FunctionalTestingFramework\Helper\MagentoFakerData
- \Magento\FunctionalTestingFramework\Module\MagentoSequence
- \Magento\FunctionalTestingFramework\Module\MagentoAssert
- \Magento\FunctionalTestingFramework\Module\MagentoActionProxies
diff --git a/etc/di.xml b/etc/di.xml
index 8d06383a5..1dd91896a 100644
--- a/etc/di.xml
+++ b/etc/di.xml
@@ -8,7 +8,7 @@
+
]>
@@ -222,6 +222,8 @@
- createDataKey
- key
- stepKey
+ - name
+ - name
- stepKey
- keyForRemoval
- keyForRemoval
@@ -239,6 +241,8 @@
- stepKey
- stepKey
+ - name
+ - name
- keyForRemoval
- keyForRemoval
- name
@@ -299,6 +303,7 @@
- name
- name
+ - name
- stepKey
- createDataKey
- key
@@ -316,6 +321,7 @@
- keyForRemoval
- name
- name
+ - name
- createDataKey
- key
diff --git a/src/Magento/FunctionalTestingFramework/Helper/Acceptance.php b/src/Magento/FunctionalTestingFramework/Helper/Acceptance.php
deleted file mode 100644
index fafe167af..000000000
--- a/src/Magento/FunctionalTestingFramework/Helper/Acceptance.php
+++ /dev/null
@@ -1,42 +0,0 @@
-getModule(MagentoWebDriver::class)->_reconfigure([$config => $value]);
- }
-
- /**
- * Get WebDriver configuration.
- *
- * @param string $config
- * @return string
- */
- public function getConfiguration($config)
- {
- return $this->getModule(MagentoWebDriver::class)->_getConfig($config);
- }
-}
diff --git a/src/Magento/FunctionalTestingFramework/Helper/AdminUrlList.php b/src/Magento/FunctionalTestingFramework/Helper/AdminUrlList.php
deleted file mode 100644
index ca96033dc..000000000
--- a/src/Magento/FunctionalTestingFramework/Helper/AdminUrlList.php
+++ /dev/null
@@ -1,189 +0,0 @@
-getMethod($method);
+ if ($method) {
+ $result = [];
+ /** @var $parameter \ReflectionParameter */
+ foreach ($method->getParameters() as $parameter) {
+ try {
+ $result[$parameter->getName()] = [
+ 'type' => $parameter->getType() === null ? null : $parameter->getType()->getName(),
+ 'variableName' => $parameter->getName(),
+ 'isOptional' => $parameter->isOptional(),
+ 'optionalValue' => $parameter->isOptional() ?
+ $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null :
+ null
+ ];
+ } catch (\ReflectionException $e) {
+ $message = $e->getMessage();
+ throw new \ReflectionException($message, 0, $e);
+ }
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/src/Magento/FunctionalTestingFramework/Helper/EntityRESTApiHelper.php b/src/Magento/FunctionalTestingFramework/Helper/EntityRESTApiHelper.php
deleted file mode 100644
index 521ddc9ee..000000000
--- a/src/Magento/FunctionalTestingFramework/Helper/EntityRESTApiHelper.php
+++ /dev/null
@@ -1,112 +0,0 @@
- 'application/json'];
-
- /**
- * Rest API client.
- *
- * @var Client
- */
- private $guzzle_client;
-
- /**
- * EntityRESTApiHelper constructor.
- * @param string $host
- * @param string $port
- */
- public function __construct($host, $port)
- {
- $this->guzzle_client = new Client([
- 'base_uri' => "http://{$host}:{$port}",
- 'timeout' => 5.0,
- ]);
- }
-
- /**
- * Submit Auth API Request.
- *
- * @param string $apiMethod
- * @param string $requestURI
- * @param string $jsonBody
- * @param array $headers
- * @return \Psr\Http\Message\ResponseInterface
- */
- public function submitAuthAPIRequest($apiMethod, $requestURI, $jsonBody, $headers)
- {
- $allHeaders = $headers;
- $authTokenVal = $this->getAuthToken();
- $authToken = ['Authorization' => 'Bearer ' . $authTokenVal];
- $allHeaders = array_merge($allHeaders, $authToken);
-
- return $this->submitAPIRequest($apiMethod, $requestURI, $jsonBody, $allHeaders);
- }
-
- /**
- * Function that sends a REST call to the integration endpoint for an authorization token.
- *
- * @return string
- */
- private function getAuthToken()
- {
- $jsonArray = json_encode(['username' => 'admin', 'password' => 'admin123']);
-
- $response = $this->submitAPIRequest(
- 'POST',
- self::INTEGRATION_ADMIN_TOKEN_URI,
- $jsonArray,
- self::APPLICATION_JSON_HEADER
- );
-
- if ($response->getStatusCode() != 200) {
- throwException($response->getReasonPhrase() .' Could not get admin token from service, please check logs.');
- }
-
- $authToken = str_replace('"', "", $response->getBody()->getContents());
- return $authToken;
- }
-
- /**
- * Function that submits an api request from the guzzle client using the following parameters:
- *
- * @param string $apiMethod
- * @param string $requestURI
- * @param string $jsonBody
- * @param array $headers
- * @return \Psr\Http\Message\ResponseInterface
- */
- private function submitAPIRequest($apiMethod, $requestURI, $jsonBody, $headers)
- {
- $response = $this->guzzle_client->request(
- $apiMethod,
- $requestURI,
- [
- 'headers' => $headers,
- 'body' => $jsonBody
- ]
- );
-
- return $response;
- }
-}
diff --git a/src/Magento/FunctionalTestingFramework/Helper/Helper.php b/src/Magento/FunctionalTestingFramework/Helper/Helper.php
new file mode 100644
index 000000000..e47aca32b
--- /dev/null
+++ b/src/Magento/FunctionalTestingFramework/Helper/Helper.php
@@ -0,0 +1,15 @@
+helpers = $helpers;
+ }
+
+ /**
+ * Returns helper object by it's class name.
+ *
+ * @param string $className
+ * @return Helper
+ * @throws TestFrameworkException
+ */
+ public function get(string $className)
+ {
+ if ($this->has($className)) {
+ return $this->helpers[$className];
+ }
+ throw new TestFrameworkException('Custom helper ' . $className . 'not found.');
+ }
+
+ /**
+ * Verifies that helper object exist.
+ *
+ * @param string $className
+ * @return boolean
+ */
+ public function has(string $className)
+ {
+ return array_key_exists($className, $this->helpers);
+ }
+}
diff --git a/src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php b/src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php
deleted file mode 100644
index 9c28a3531..000000000
--- a/src/Magento/FunctionalTestingFramework/Helper/MagentoFakerData.php
+++ /dev/null
@@ -1,122 +0,0 @@
- $faker->title,
- 'firstname' => $faker->firstName,
- 'middlename' => $faker->firstName,
- 'lastname' => $faker->lastName,
- 'suffix' => \Faker\Provider\en_US\Person::suffix(),
- 'email' => $faker->email,
- 'dateOfBirth' => $faker->date('m/d/Y', 'now'),
- 'gender' => rand(0, 1),
- 'group_id' => 1,
- 'store_id' => 1,
- 'website_id' => 1,
- 'taxVatNumber' => \Faker\Provider\at_AT\Payment::vat(),
- 'company' => $faker->company,
- 'phoneNumber' => $faker->phoneNumber,
- 'address' => [
- 'address1' => $faker->streetAddress,
- 'address2' => $faker->streetAddress,
- 'city' => $faker->city,
- 'country' => 'United States',
- 'state' => \Faker\Provider\en_US\Address::state(),
- 'zipCode' => $faker->postcode
- ]
- ];
- return array_merge($customerData, $additional);
- }
-
- /**
- * Get category data.
- *
- * @return array
- */
- public function getCategoryData()
- {
- $faker = \Faker\Factory::create();
-
- return [
- 'enableCategory' => $faker->boolean(),
- 'includeInMenu' => $faker->boolean(),
- 'categoryName' => $faker->md5,
- 'categoryImage' => '',
- 'description' => $faker->sentence(10, true),
- 'addCMSBlock' => '',
-
- 'urlKey' => $faker->uuid,
- 'metaTitle' => $faker->word,
- 'metaKeywords' => $faker->sentence(5, true),
- 'metaDescription' => $faker->sentence(10, true),
- ];
- }
-
- /**
- * Get simple product data.
- *
- * @return array
- */
- public function getProductData()
- {
- $faker = \Faker\Factory::create();
- return [
- 'enableProduct' => $faker->boolean(),
- 'attributeSet' => '',
- 'productName' => $faker->text(20),
- 'sku' => \Faker\Provider\DateTime::unixTime('now'),
- 'price' => $faker->randomFloat(2, 0, 999),
- 'quantity' => $faker->numberBetween(1, 999),
-
- 'urlKey' => $faker->uuid,
- 'metaTitle' => $faker->word,
- 'metaKeywords' => $faker->sentence(5, true),
- 'metaDescription' => $faker->sentence(10, true)
- ];
- }
-
- /**
- * Get Content Page Data.
- *
- * @return array
- */
- public function getContentPage()
- {
- $faker = \Faker\Factory::create();
-
- $pageContent = [
- 'pageTitle' => $faker->sentence(3, true),
- 'contentHeading' => $faker->sentence(3, true),
- 'contentBody' => $faker->sentence(10, true),
- 'urlKey' => $faker->uuid,
- 'metaTitle' => $faker->word,
- 'metaKeywords' => $faker->sentence(5, true),
- 'metaDescription' => $faker->sentence(10, true),
- 'from' => $faker->date($format = 'm/d/Y', 'now'),
- 'to' => $faker->date($format = 'm/d/Y')
- ];
- $pageContent['layoutUpdateXml'] = "ToveJaniReminder";
- $pageContent['layoutUpdateXml'] .= "Don't forget me this weekend!";
-
- return $pageContent;
- }
-}
diff --git a/src/Magento/FunctionalTestingFramework/Helper/views/TestInjectMethod.mustache b/src/Magento/FunctionalTestingFramework/Helper/views/TestInjectMethod.mustache
new file mode 100644
index 000000000..d921120cf
--- /dev/null
+++ b/src/Magento/FunctionalTestingFramework/Helper/views/TestInjectMethod.mustache
@@ -0,0 +1,19 @@
+ /**
+ * @var \Magento\FunctionalTestingFramework\Helper\HelperContainer
+ */
+ private $helperContainer;
+
+ /**
+ * Special method which automatically creates the respective objects.
+ */
+ public function _inject(
+ {{argumentsWithTypes}}
+ ) {
+ $this->helperContainer = new \Magento\FunctionalTestingFramework\Helper\HelperContainer(
+ [
+ {{#arguments}}
+ '{{type}}' => {{var}},
+ {{/arguments}}
+ ]
+ );
+ }
diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php
index dc1b158e1..3e1afae31 100644
--- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php
+++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php
@@ -8,7 +8,6 @@
use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException;
use Magento\FunctionalTestingFramework\Test\Util\ActionMergeUtil;
-use Magento\FunctionalTestingFramework\Test\Util\ObjectExtension;
/**
* Class ActionGroupObject
diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php
index 0ae3d336e..648471c7a 100644
--- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php
+++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php
@@ -75,6 +75,7 @@ class ActionObject
const DEFAULT_COMMAND_WAIT_TIMEOUT = 60;
const ACTION_ATTRIBUTE_USERINPUT = 'userInput';
const ACTION_TYPE_COMMENT = 'comment';
+ const ACTION_TYPE_HELPER = 'helper';
const INVISIBLE_STEP_ACTIONS = ['retrieveEntityField', 'getSecret'];
/**
@@ -282,6 +283,7 @@ public function setTimeout($timeout)
public function resolveReferences()
{
if (empty($this->resolvedCustomAttributes)) {
+ $this->resolveHelperReferences();
$this->trimAssertionAttributes();
$this->resolveSelectorReferenceAndTimeout();
$this->resolveUrlReference();
@@ -293,6 +295,64 @@ public function resolveReferences()
}
}
+ /**
+ * Resolves references for helpers.
+ *
+ * @throws TestReferenceException
+ * @return void
+ */
+ private function resolveHelperReferences()
+ {
+ if ($this->getType() !== 'helper') {
+ return;
+ }
+ $isResolved = false;
+
+ try {
+ foreach ($this->actionAttributes as $attrKey => $attrValue) {
+ $this->actionAttributes[$attrKey] = $this->findAndReplaceReferences(
+ SectionObjectHandler::getInstance(),
+ $attrValue
+ );
+ }
+ $isResolved = true;
+ } catch (\Exception $e) {
+ // catching exception to allow other entity type resolution to proceed
+ }
+
+ try {
+ foreach ($this->actionAttributes as $attrKey => $attrValue) {
+ $this->actionAttributes[$attrKey] = $this->findAndReplaceReferences(
+ PageObjectHandler::getInstance(),
+ $attrValue
+ );
+ }
+ $isResolved = true;
+ } catch (\Exception $e) {
+ // catching exception to allow other entity type resolution to proceed
+ }
+
+ try {
+ foreach ($this->actionAttributes as $attrKey => $attrValue) {
+ $this->actionAttributes[$attrKey] = $this->findAndReplaceReferences(
+ DataObjectHandler::getInstance(),
+ $attrValue
+ );
+ }
+ $isResolved = true;
+ } catch (\Exception $e) {
+ // catching exception to allow other entity type resolution to proceed
+ }
+
+ if ($isResolved !== true) {
+ throw new TestReferenceException(
+ "Could not resolve entity reference \"{$attrValue}\" "
+ . "in Action with stepKey \"{$this->getStepKey()}\"",
+ ["input" => $attrValue, "stepKey" => $this->getStepKey()]
+ );
+ }
+ }
+
/**
* Flattens expectedResult/actualResults/array nested elements, if necessary.
* e.g. expectedResults[] -> ["expectedType" => "string", "expected" => "value"]
diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php
index fc874fa24..d9b8d32fb 100644
--- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php
+++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionObjectExtractor.php
@@ -22,6 +22,7 @@ class ActionObjectExtractor extends BaseObjectExtractor
const TEST_ACTION_AFTER = 'after';
const TEST_STEP_MERGE_KEY = 'stepKey';
const ACTION_GROUP_TAG = 'actionGroup';
+ const HELPER_TAG = 'helper';
const ACTION_GROUP_REF = 'ref';
const ACTION_GROUP_ARGUMENTS = 'arguments';
const ACTION_GROUP_ARG_VALUE = 'value';
@@ -84,6 +85,7 @@ public function extractActions($testActions, $testName = null)
}
$actionAttributes = $this->processActionGroupArgs($actionType, $actionAttributes);
+ $actionAttributes = $this->processHelperArgs($actionType, $actionAttributes);
$linkedAction = $this->processLinkedActions($actionName, $actionData);
$actions = $this->extractFieldActions($actionData, $actions);
$actionAttributes = $this->extractFieldReferences($actionData, $actionAttributes);
@@ -167,6 +169,42 @@ private function processActionGroupArgs($actionType, $actionAttributeData)
return $actionAttributeArgData;
}
+ /**
+ * Takes the helper arguments as an array that can be passed to PHP class
+ * defined in the action group xml.
+ *
+ * @param string $actionType
+ * @param array $actionAttributeData
+ * @return array
+ * @throws TestFrameworkException
+ */
+ private function processHelperArgs($actionType, $actionAttributeData)
+ {
+ $reservedHelperVariableNames = ['class', 'method'];
+ if ($actionType !== self::HELPER_TAG) {
+ return $actionAttributeData;
+ }
+
+ $actionAttributeArgData = [];
+ foreach ($actionAttributeData as $attributeDataKey => $attributeDataValues) {
+ if (isset($attributeDataValues['nodeName']) && $attributeDataValues['nodeName'] == 'argument') {
+ if (isset($attributeDataValues['name'])
+ && in_array($attributeDataValues['name'], $reservedHelperVariableNames)) {
+ $message = 'Helper argument names ' . implode(',', $reservedHelperVariableNames);
+ $message .= ' are reserved and can not be used.';
+ throw new TestFrameworkException(
+ $message
+ );
+ }
+ $actionAttributeArgData[$attributeDataValues['name']] = $attributeDataValues['value'] ?? null;
+ continue;
+ }
+ $actionAttributeArgData[$attributeDataKey] = $attributeDataValues;
+ }
+
+ return $actionAttributeArgData;
+ }
+
/**
* Takes the array representing an action and validates it is a persistence type. If of type persistence,
* the function checks for any user specified fields to extract as separate actions to be resolved independently
diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd
index 8670d9885..fbb21456f 100644
--- a/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd
+++ b/src/Magento/FunctionalTestingFramework/Test/etc/Actions/customActions.xsd
@@ -11,6 +11,7 @@
+
@@ -29,6 +30,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php
index e0543463d..19319d0d7 100644
--- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php
+++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php
@@ -25,6 +25,8 @@
use Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil;
use Magento\FunctionalTestingFramework\Test\Util\ActionMergeUtil;
use Magento\FunctionalTestingFramework\Util\Path\FilePathFormatter;
+use Mustache_Engine;
+use Mustache_Loader_FilesystemLoader;
/**
* Class TestGenerator
@@ -60,6 +62,13 @@ class TestGenerator
const ARRAY_WRAP_OPEN = '[';
const ARRAY_WRAP_CLOSE = ']';
+ /**
+ * Array with helpers classes and methods.
+ *
+ * @var array
+ */
+ private $customHelpers = [];
+
/**
* Actor name for AcceptanceTest
*
@@ -268,6 +277,7 @@ public function assembleTestPhp($testObject)
$cestPhp .= $classAnnotationsPhp;
$cestPhp .= sprintf("class %s\n", $className);
$cestPhp .= "{\n";
+ $cestPhp .= $this->generateInjectMethod();
$cestPhp .= $hookPhp;
$cestPhp .= $testsPhp;
$cestPhp .= "}\n";
@@ -275,6 +285,35 @@ public function assembleTestPhp($testObject)
return $cestPhp;
}
+ /**
+ * Generates _injectMethod based on $this->customHelpers.
+ *
+ * @return string
+ */
+ private function generateInjectMethod()
+ {
+ if (empty($this->customHelpers)) {
+ return "";
+ }
+
+ $mustacheEngine = new Mustache_Engine([
+ 'loader' => new Mustache_Loader_FilesystemLoader(
+ dirname(__DIR__) . DIRECTORY_SEPARATOR . "Helper" . DIRECTORY_SEPARATOR . 'views'
+ )
+ ]);
+
+ $argumentsWithType = [];
+ $arguments = [];
+ foreach ($this->customHelpers as $customHelperVar => $customHelperType) {
+ $argumentsWithType[] = $customHelperType . ' ' . $customHelperVar;
+ $arguments[] = ['type' => $customHelperType, 'var' => $customHelperVar];
+ }
+ $mustacheData['argumentsWithTypes'] = implode(', ' . PHP_EOL, $argumentsWithType);
+ $mustacheData['arguments'] = $arguments;
+
+ return $mustacheEngine->render('TestInjectMethod', $mustacheData);
+ }
+
/**
* Load ALL Test objects. Loop over and pass each to the assembleTestPhp function.
*
@@ -774,6 +813,45 @@ public function generateStepsPhp($actionObjects, $generationScope = TestGenerato
}
switch ($actionObject->getType()) {
+ case "helper":
+ if (!in_array($customActionAttributes['class'], $this->customHelpers)) {
+ $this->customHelpers['$' . $stepKey] = $customActionAttributes['class'];
+ }
+
+ $arguments = [];
+ $classReader = new \Magento\FunctionalTestingFramework\Helper\Code\ClassReader();
+ $parameters = $classReader->getParameters(
+ $customActionAttributes['class'],
+ $customActionAttributes['method']
+ );
+ $errors = [];
+ foreach ($parameters as $parameter) {
+ if (array_key_exists($parameter['variableName'], $customActionAttributes)) {
+ $value = $customActionAttributes[$parameter['variableName']];
+ $arguments[] = $this->addUniquenessFunctionCall(
+ $value,
+ $parameter['type'] === 'string' || $parameter['type'] === null
+ );
+ } elseif ($parameter['isOptional']) {
+ $value = $parameter['optionalValue'];
+ $arguments[] = str_replace(PHP_EOL, '', var_export($value, true));
+ } else {
+ $errors[] = 'Argument \'' . $parameter['variableName'] . '\' for method '
+ . $customActionAttributes['class'] . '::' . $customActionAttributes['method']
+ . ' is not found.';
+ }
+ }
+ if (!empty($errors)) {
+ throw new TestFrameworkException(implode(PHP_EOL, $errors));
+ }
+ $testSteps .= sprintf(
+ "\t\t$%s->comment('[%s] %s()');" . PHP_EOL,
+ $actor,
+ $stepKey,
+ $customActionAttributes['class'] . '::' . $customActionAttributes['method']
+ );
+ $testSteps .= $this->wrapFunctionCall($actor, $actionObject, $arguments);
+ break;
case "createData":
$entity = $customActionAttributes['entity'];
@@ -1841,7 +1919,15 @@ private function addDollarSign($input)
private function wrapFunctionCall($actor, $action, ...$args)
{
$isFirst = true;
- $output = sprintf("\t\t$%s->%s(", $actor, $action->getType());
+ $isActionHelper = $action->getType() === 'helper';
+ $actionType = $action->getType();
+ if ($isActionHelper) {
+ $actor = "this->helperContainer->get('" . $action->getCustomActionAttributes()['class'] . "')";
+ $args = $args[0];
+ $actionType = $action->getCustomActionAttributes()['method'];
+ }
+
+ $output = sprintf("\t\t$%s->%s(", $actor, $actionType);
for ($i = 0; $i < count($args); $i++) {
if (null === $args[$i]) {
continue;