From b3bf4eb189057c0d3c98fda34a969fa0790e6b9a Mon Sep 17 00:00:00 2001 From: Ian Meron Date: Thu, 26 Oct 2017 15:42:32 -0500 Subject: [PATCH 01/29] MQE-388: Write store settings before tests - add new metadata generator util - add new example input file - change dir setup util to exposer public recursive delete (cherry picked from commit 8d698c4) --- .../Util/Filesystem/DirSetupUtil.php | 2 +- .../MetadataGenerator/MetadataGenUtil.php | 168 ++++++++++++++++++ .../_generateMetadtataFile.php | 18 ++ .../Util/MetadataGenerator/input.yml.sample | 4 + .../views/operation.mustache | 13 ++ .../views/partials/field.mustache | 1 + .../views/partials/object.mustache | 10 ++ 7 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/MetadataGenUtil.php create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/_generateMetadtataFile.php create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/input.yml.sample create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/operation.mustache create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/partials/field.mustache create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/partials/object.mustache diff --git a/src/Magento/FunctionalTestingFramework/Util/Filesystem/DirSetupUtil.php b/src/Magento/FunctionalTestingFramework/Util/Filesystem/DirSetupUtil.php index 405b2a4f7..32c03966e 100644 --- a/src/Magento/FunctionalTestingFramework/Util/Filesystem/DirSetupUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/Filesystem/DirSetupUtil.php @@ -32,7 +32,7 @@ public static function createGroupDir($fullPath) * @param string $directory * @return void */ - private static function rmdirRecursive($directory) + public static function rmdirRecursive($directory) { $it = new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS); diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/MetadataGenUtil.php b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/MetadataGenUtil.php new file mode 100644 index 000000000..6b189d1f3 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/MetadataGenUtil.php @@ -0,0 +1,168 @@ +operationName = $operationName; + $this->operationDataType = $operationDataType; + $this->operationUrl = $operationUrl; + $this->inputString = $inputString; + } + + /** + * Function which takes params from constructor, transforms into data array and outputs a representative metadata + * file for MFTF to consume and send requests. + * + * @return void + */ + public function generateMetadataFile() + { + $this->initMustacheTemplates(); + + // parse the string params into an array + parse_str($this->inputString, $results); + $data = $this->convertResultToEntry($results, $this->operationDataType); + $data = $this->appendParentParams($data); + $output = $this->mustache_engine->render('operation', $data); + $this->cleanAndCreateOutputDir(); + file_put_contents( + self::OUTPUT_DIR . DIRECTORY_SEPARATOR . $this->operationDataType . "-meta.xml", + $output + ); + } + + /** + * Function which initializes mustache templates for file generation. + * + * @return void + */ + private function initMustacheTemplates() + { + $this->mustache_engine = new Mustache_Engine( + ['loader' => new Mustache_Loader_FilesystemLoader("views"), + 'partials_loader' => new Mustache_Loader_FilesystemLoader( + "views" . DIRECTORY_SEPARATOR . "partials" + )] + ); + } + + /** + * Function which takes the top level params from the user and returns an array appended with the needed config. + * + * @param array $data + * @return array + */ + private function appendParentParams($data) + { + $result = $data; + $result['operationName'] = $this->operationName; + $result['operationDataType'] = $this->operationDataType; + $result['operationUrl'] = $this->operationUrl; + + return $result; + } + + /** + * Function which is called recursively to generate the mustache array for the template enging. Makes decisions + * about type and format based on parameter array. + * + * @param array $results + * @param string $defaultDataType + * @return array + */ + private function convertResultToEntry($results, $defaultDataType) + { + $data = []; + + foreach ($results as $key => $result) { + $entry = []; + if (is_array($result)) { + $entry = array_merge($entry, ['objectName' => $key]); + $res = $this->convertResultToEntry($result, $defaultDataType); + if (!array_key_exists('objects', $res)) { + $entry = array_merge($entry, ['objects' => null]); + $entry = array_merge($entry, ['dataType' => $key]); + } else { + $entry = array_merge($entry, ['hasChildObj' => true]); + $entry = array_merge($entry, ['dataType' => $defaultDataType]); + } + $data['objects'][] = array_merge($entry, $res); + } else { + $data['fields'][] = ['fieldName' => $key]; + } + } + + return $data; + } + + /** + * Function which cleans and creates the _output dir. + * + * @return void + */ + private function cleanAndCreateOutputDir() + { + if (file_exists(self::OUTPUT_DIR)) { + \Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil::rmdirRecursive(self::OUTPUT_DIR); + } + + mkdir(self::OUTPUT_DIR); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/_generateMetadtataFile.php b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/_generateMetadtataFile.php new file mode 100644 index 000000000..3ccbb764d --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/_generateMetadtataFile.php @@ -0,0 +1,18 @@ +generateMetadataFile(); diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/input.yml.sample b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/input.yml.sample new file mode 100644 index 000000000..503aef067 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/input.yml.sample @@ -0,0 +1,4 @@ +operationName: createMyEntity +operationDataType: myEntityType +operationUrl: /admin/system_config/save/someEntity +inputString: entity[param1]=value1&entity[param2]=value2&entity[param3]=value3&entityField=field1 diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/operation.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/operation.mustache new file mode 100644 index 000000000..f3ba9ddfe --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/operation.mustache @@ -0,0 +1,13 @@ + + + + + + {{>object}} + + \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/partials/field.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/partials/field.mustache new file mode 100644 index 000000000..284835ef2 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/partials/field.mustache @@ -0,0 +1 @@ +string diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/partials/object.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/partials/object.mustache new file mode 100644 index 000000000..2e7210a8f --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/partials/object.mustache @@ -0,0 +1,10 @@ +{{#objects}} + +{{#fields}} + {{> field}} +{{/fields}} +{{#hasChildObj}} + {{> object}} +{{/hasChildObj}} + +{{/objects}} \ No newline at end of file From 541a42b05645c5e5ebf56af30f5cec111f1ff3c8 Mon Sep 17 00:00:00 2001 From: Ian Meron Date: Fri, 27 Oct 2017 10:53:35 -0500 Subject: [PATCH 02/29] MQE-388: Write store settings before tests - change output deletion beahvior - fix codesniffer method (cherry picked from commit 63dfb63) --- .../MetadataGenerator/MetadataGenUtil.php | 21 ++++++++++++++----- .../_generateMetadtataFile.php | 5 +++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/MetadataGenUtil.php b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/MetadataGenUtil.php index 6b189d1f3..2015a2554 100644 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/MetadataGenUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/MetadataGenUtil.php @@ -50,6 +50,13 @@ class MetadataGenUtil */ private $inputString; + /** + * The relative filepath for the *meta.xml file to be generated. + * + * @var string + */ + private $filepath; + /** * MetadataGenUtil constructor. * @@ -64,6 +71,8 @@ public function __construct($operationName, $operationDataType, $operationUrl, $ $this->operationDataType = $operationDataType; $this->operationUrl = $operationUrl; $this->inputString = $inputString; + + $this->filepath = self::OUTPUT_DIR . DIRECTORY_SEPARATOR . $this->operationDataType . "-meta.xml"; } /** @@ -83,7 +92,7 @@ public function generateMetadataFile() $output = $this->mustache_engine->render('operation', $data); $this->cleanAndCreateOutputDir(); file_put_contents( - self::OUTPUT_DIR . DIRECTORY_SEPARATOR . $this->operationDataType . "-meta.xml", + $this->filepath, $output ); } @@ -153,16 +162,18 @@ private function convertResultToEntry($results, $defaultDataType) } /** - * Function which cleans and creates the _output dir. + * Function which cleans any previously created fileand creates the _output dir. * * @return void */ private function cleanAndCreateOutputDir() { - if (file_exists(self::OUTPUT_DIR)) { - \Magento\FunctionalTestingFramework\Util\Filesystem\DirSetupUtil::rmdirRecursive(self::OUTPUT_DIR); + if (!file_exists(self::OUTPUT_DIR)) { + mkdir(self::OUTPUT_DIR); } - mkdir(self::OUTPUT_DIR); + if (file_exists($this->filepath)) { + unlink($this->filepath); + } } } diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/_generateMetadtataFile.php b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/_generateMetadtataFile.php index 3ccbb764d..25aa7ee19 100644 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/_generateMetadtataFile.php +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/_generateMetadtataFile.php @@ -1,4 +1,9 @@ Date: Thu, 2 Nov 2017 11:20:28 -0500 Subject: [PATCH 03/29] MQE-472: refactored entity update mechanism and removed path param type. --- .../OperationDefinitionObjectHandler.php | 4 +- .../DataGenerator/Persist/CurlHandler.php | 4 +- .../Persist/DataPersistenceHandler.php | 14 ++++- .../DataGenerator/etc/dataOperation.xsd | 1 - .../Util/TestGenerator.php | 61 +++++++++++-------- 5 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php index 9dda26324..0fb40aa7d 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/OperationDefinitionObjectHandler.php @@ -28,7 +28,6 @@ class OperationDefinitionObjectHandler implements ObjectHandlerInterface const ENTITY_OPERATION_HEADER_PARAM = 'param'; const ENTITY_OPERATION_HEADER_VALUE = 'value'; const ENTITY_OPERATION_URL_PARAM = 'param'; - const ENTITY_OPERATION_URL_PARAM_TYPE = 'type'; const ENTITY_OPERATION_URL_PARAM_KEY = 'key'; const ENTITY_OPERATION_URL_PARAM_VALUE = 'value'; const ENTITY_OPERATION_ENTRY = 'field'; @@ -156,8 +155,7 @@ private function initDataDefinitions() if (array_key_exists(OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM, $opDefArray)) { foreach ($opDefArray[OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM] as $paramEntry) { - $params[$paramEntry[OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_TYPE]] - [$paramEntry[OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_KEY]] = + $params[$paramEntry[OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_KEY]] = $paramEntry[OperationDefinitionObjectHandler::ENTITY_OPERATION_URL_PARAM_VALUE]; } } diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php index a4a574dd2..de22fb99d 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/CurlHandler.php @@ -106,9 +106,7 @@ public function executeRequest($dependentEntities) $successRegex = null; $returnRegex = null; - if ($this->operation == 'update') { - $entities = array_merge($dependentEntities, [$this->entityObject]); - } elseif ((null !== $dependentEntities) && is_array($dependentEntities)) { + if ((null !== $dependentEntities) && is_array($dependentEntities)) { $entities = array_merge([$this->entityObject], $dependentEntities); } else { $entities = [$this->entityObject]; diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php index d69595f7c..d28d87300 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Persist/DataPersistenceHandler.php @@ -7,6 +7,7 @@ namespace Magento\FunctionalTestingFramework\DataGenerator\Persist; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; /** * Class DataPersistenceHandler @@ -80,17 +81,24 @@ public function createEntity($storeCode = null) /** * Function which executes a put request based on specific operation metadata. * + * @param string $updateDataName + * @param array $updateDependentObjects * @param string $storeCode * @return void */ - public function updateEntity($storeCode = null) + public function updateEntity($updateDataName, $updateDependentObjects = [], $storeCode = null) { if (!empty($storeCode)) { $this->storeCode = $storeCode; } - $curlHandler = new CurlHandler('update', $this->entityObject, $this->storeCode); - $result = $curlHandler->executeRequest($this->dependentObjects); + + foreach ($updateDependentObjects as $dependentObject) { + $this->dependentObjects[] = $dependentObject->getCreatedObject(); + } + $updateEntityObject = DataObjectHandler::getInstance()->getObject($updateDataName); + $curlHandler = new CurlHandler('update', $updateEntityObject, $this->storeCode); + $result = $curlHandler->executeRequest(array_merge($this->dependentObjects, [$this->createdObject])); $this->setCreatedObject( $result, null, diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd index 7126fa67e..7d4cc80d3 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd @@ -72,7 +72,6 @@ - diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index f1c2b630a..7219d78cf 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -544,40 +544,48 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) } break; case "updateData": - $entity = $customActionAttributes['entity']; - $originalEntity = null; - if (isset($customActionAttributes['createDataKey'])) { - $originalEntity = $customActionAttributes['createDataKey']; - } - $key = $steps->getMergeKey(); + $key = $customActionAttributes['createDataKey']; + $updateEntity = $customActionAttributes['entity']; + //Add an informative statement to help the user debug test runs $testSteps .= sprintf( - "\t\t$%s->amGoingTo(\"update entity that has the mergeKey: %s\");\n", + "\t\t$%s->amGoingTo(\"update entity that has the createdDataKey: %s\");\n", $actor, $key ); - //Get Entity from Static data. - $testSteps .= sprintf( - "\t\t$%s = DataObjectHandler::getInstance()->getObject(\"%s\");\n", - $entity, - $entity - ); + + //HookObject End-Product needs to be created in the Class/Cest scope, + //otherwise create them in the Test scope. + //Determine if there are required-entities and create array of required-entities for merging. + $requiredEntities = []; + $requiredEntityObjects = []; + foreach ($customActionAttributes as $customAttribute) { + if (is_array($customAttribute) && $customAttribute['nodeName'] = 'required-entity') { + if ($hookObject) { + $requiredEntities [] = "\$this->" . $customAttribute[self::REQUIRED_ENTITY_REFERENCE] . + "->getName() => " . "\$this->" . $customAttribute[self::REQUIRED_ENTITY_REFERENCE] . + "->getType()"; + $requiredEntityObjects [] = '$this->' . $customAttribute + [self::REQUIRED_ENTITY_REFERENCE]; + } else { + $requiredEntities [] = "\$" . $customAttribute[self::REQUIRED_ENTITY_REFERENCE] + . "->getName() => " . "\$" . $customAttribute[self::REQUIRED_ENTITY_REFERENCE] . + "->getType()"; + $requiredEntityObjects [] = '$' . $customAttribute[self::REQUIRED_ENTITY_REFERENCE]; + } + } + } if ($hookObject) { - $updateEntityFunctionCall = sprintf("\t\t\$this->%s->updateEntity(", $key); - $dataPersistenceHandlerFunctionCall = sprintf( - "\t\t\$this->%s = new DataPersistenceHandler($%s, [\$this->%s]);\n", - $key, - $entity, - $originalEntity - ); + $updateEntityFunctionCall = sprintf("\t\t\$this->%s->updateEntity(\"%s\"", $key, $updateEntity); } else { - $updateEntityFunctionCall = sprintf("\t\t\$%s->updateEntity(", $key); - $dataPersistenceHandlerFunctionCall = sprintf( - "\t\t$%s = new DataPersistenceHandler($%s, [$%s]);\n", - $key, - $entity, - $originalEntity + $updateEntityFunctionCall = sprintf("\t\t\$%s->updateEntity(\"%s\"", $key, $updateEntity); + } + + if (!empty($requiredEntities)) { + $updateEntityFunctionCall .= sprintf( + ", [%s]", + implode(', ', $requiredEntityObjects) ); } @@ -587,7 +595,6 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) $updateEntityFunctionCall .= ");\n"; } - $testSteps .= $dataPersistenceHandlerFunctionCall; $testSteps .= $updateEntityFunctionCall; break; case "getData": From 4acbb80267139edba0b6c35f8e8ac075168e3b55 Mon Sep 17 00:00:00 2001 From: Ian Meron Date: Mon, 6 Nov 2017 15:02:57 -0600 Subject: [PATCH 04/29] MQE-508: before and after tags should have their own group/type in the schema - add new type for before/after schema --- .../FunctionalTestingFramework/Test/etc/testSchema.xsd | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd index d6cd059b3..fcd54a924 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd @@ -22,8 +22,8 @@ - - + + @@ -66,6 +66,11 @@ + + + + + From 284ec7ba72835fa60732a21c04937a5b8fee1969 Mon Sep 17 00:00:00 2001 From: Ian Meron Date: Mon, 6 Nov 2017 14:24:56 -0600 Subject: [PATCH 05/29] MQE-483: Sanitize test naming to prevent Jenkins build failure - add new validation util - update test object extractor to use validation util - add new unit test --- .../Test/Util/TestNameValidationUtilTest.php | 73 +++++++++++++++++++ .../Test/Util/TestNameValidationUtil.php | 32 ++++++++ .../Test/Util/TestObjectExtractor.php | 3 + 3 files changed, 108 insertions(+) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/TestNameValidationUtilTest.php create mode 100644 src/Magento/FunctionalTestingFramework/Test/Util/TestNameValidationUtil.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/TestNameValidationUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/TestNameValidationUtilTest.php new file mode 100644 index 000000000..6e8b3d598 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/TestNameValidationUtilTest.php @@ -0,0 +1,73 @@ +validateBlacklistedTestName("{{curlyBraces}}"); + } + + /** + * Validate name with quotation marks throws exception + */ + public function testQuotesInTestName() + { + $this->validateBlacklistedTestName("\"quotes\""); + } + + /** + * Validate name with single quotes throws exception + */ + public function testSingleQuotesInTestName() + { + $this->validateBlacklistedTestName("'singleQuotes'"); + } + + /** + * Validate name with parenthesis throws execption + */ + public function testParenthesesInTestName() + { + $this->validateBlacklistedTestName("(parenthesis)"); + } + + /** + * Validate name with dollar signs throws exception + */ + public function testDollarSignInTestName() + { + $this->validateBlacklistedTestName("\$dollarSign\$"); + } + + /** + * Validate name with spaces throws exception + */ + public function testSpacesInTestName() + { + $this->validateBlacklistedTestName("Test Name With Spaces"); + } + + /** + * Method which takes the name of the test expecting an invalid char. Runs the validation method against name. + * + * @param string $testName + */ + private function validateBlacklistedTestName($testName) + { + $this->expectException(XmlException::class); + TestNameValidationUtil::validateName($testName); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestNameValidationUtil.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestNameValidationUtil.php new file mode 100644 index 000000000..1eef74a77 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestNameValidationUtil.php @@ -0,0 +1,32 @@ +stripDescriptorTags( $testData, From 44428add99d870e3dafe9b8db26be45d672ed96a Mon Sep 17 00:00:00 2001 From: Ian Meron Date: Wed, 8 Nov 2017 11:16:44 -0600 Subject: [PATCH 06/29] MQE-483: Sanitize test naming to prevent Jenkins build failure - add invalid char to error message, review feedback --- .../Test/Util/TestNameValidationUtilTest.php | 1 + .../Test/Util/TestNameValidationUtil.php | 30 ++++++++++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/TestNameValidationUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/TestNameValidationUtilTest.php index 6e8b3d598..8b50062ed 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/TestNameValidationUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/TestNameValidationUtilTest.php @@ -64,6 +64,7 @@ public function testSpacesInTestName() * Method which takes the name of the test expecting an invalid char. Runs the validation method against name. * * @param string $testName + * @return void */ private function validateBlacklistedTestName($testName) { diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestNameValidationUtil.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestNameValidationUtil.php index 1eef74a77..a4306de83 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestNameValidationUtil.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestNameValidationUtil.php @@ -10,7 +10,17 @@ class TestNameValidationUtil { - const BLACKLISTED_CHAR = [" ", ",", "'", "\"" , "{", "}", "$", "(", ")" ]; + const BLACKLISTED_CHAR = [ + " " => "spaces", + "," => "commas", + "'" => "single quotes", + "\"" => "double quotes", + "{" => "curly braces", + "}" => "curly braces", + "$" => "dollar signs", + "(" => "parenthesis", + ")" => "parenthesis" + ]; /** * Function which runs a validation against the blacklisted char defined in this class. Validation occurs to insure @@ -24,9 +34,21 @@ public static function validateName($testName) { $testChars = str_split($testName); - $diff = array_diff($testChars, self::BLACKLISTED_CHAR); - if (count($diff) != count($testChars)) { - throw new XmlException("Test name ${testName} contains illegal characters, please fix and re-run"); + $diff = array_intersect($testChars, array_keys(self::BLACKLISTED_CHAR)); + if (count($diff) > 0) { + $errorMessage = "Test name \"${testName}\" contains illegal characters, please fix and re-run."; + $uniqueDiff = array_unique(array_map(['self', 'nameMapper'], $diff)); + + foreach ($uniqueDiff as $diffChar) { + $errorMessage .= "\nTest names cannot contain " . $diffChar; + } + + throw new XmlException($errorMessage); } } + + private static function nameMapper($val) + { + return self::BLACKLISTED_CHAR[$val]; + } } From 26a59c791a26d67c6bc6e6c60ae687f3936b6671 Mon Sep 17 00:00:00 2001 From: Ian Meron Date: Wed, 8 Nov 2017 11:21:32 -0600 Subject: [PATCH 07/29] MQE-483: Sanitize test naming to prevent Jenkins build failure - fix for codesniffer, missed phpDoc --- .../Test/Util/TestNameValidationUtil.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/TestNameValidationUtil.php b/src/Magento/FunctionalTestingFramework/Test/Util/TestNameValidationUtil.php index a4306de83..d3796621e 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/TestNameValidationUtil.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/TestNameValidationUtil.php @@ -47,6 +47,12 @@ public static function validateName($testName) } } + /** + * Function which maps the blacklisted char to its name, function is used by the array map above. + * + * @param string $val + * @return string + */ private static function nameMapper($val) { return self::BLACKLISTED_CHAR[$val]; From 42b677dce83bdf7491c1a293c888b12b1dd8fe15 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Thu, 9 Nov 2017 14:00:53 -0600 Subject: [PATCH 08/29] MQE-432: Create variable reference verification tests - Created all verification tests. - Quick bugfix for conditionalClick in di.xml - Add Uniqueness Call to dependentSelector. - Remove previous persistedReplacement test. --- .../Resources/DataReplacementCest.txt | 48 ++++++++++++ .../Resources/PageReplacementCest.txt | 41 ++++++++++ .../Resources/PersistedReplacementCest.txt | 41 +++------- .../Resources/SectionReplacementCest.txt | 59 ++++++++++++++ .../Cest/PersistedReplacementCest.xml | 67 ---------------- .../TestModule/Cest/dataReplacementCest.xml | 36 +++++++++ .../TestModule/Cest/pageReplacementCest.xml | 24 ++++++ .../Cest/persistedReplacementCest.xml | 28 +++++++ .../Cest/sectionReplacementCest.xml | 48 ++++++++++++ .../TestModule/Data/replacementData.xml | 21 +++++ .../TestModule/Page/SamplePage.xml | 9 +++ .../TestModule/Section/SampleSection.xml | 2 + .../PersistedReplacementGenerationTest.php | 38 ---------- .../ReferenceReplacementGenerationTest.php | 76 +++++++++++++++++++ etc/di.xml | 8 +- .../Test/Objects/ActionObject.php | 1 + .../Util/TestGenerator.php | 2 +- 17 files changed, 410 insertions(+), 139 deletions(-) create mode 100644 dev/tests/verification/Resources/DataReplacementCest.txt create mode 100644 dev/tests/verification/Resources/PageReplacementCest.txt create mode 100644 dev/tests/verification/Resources/SectionReplacementCest.txt delete mode 100644 dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml create mode 100644 dev/tests/verification/TestModule/Cest/dataReplacementCest.xml create mode 100644 dev/tests/verification/TestModule/Cest/pageReplacementCest.xml create mode 100644 dev/tests/verification/TestModule/Cest/persistedReplacementCest.xml create mode 100644 dev/tests/verification/TestModule/Cest/sectionReplacementCest.xml create mode 100644 dev/tests/verification/TestModule/Data/replacementData.xml delete mode 100644 dev/tests/verification/Tests/PersistedReplacementGenerationTest.php create mode 100644 dev/tests/verification/Tests/ReferenceReplacementGenerationTest.php diff --git a/dev/tests/verification/Resources/DataReplacementCest.txt b/dev/tests/verification/Resources/DataReplacementCest.txt new file mode 100644 index 000000000..60f847bb4 --- /dev/null +++ b/dev/tests/verification/Resources/DataReplacementCest.txt @@ -0,0 +1,48 @@ +fillField("#selector", "StringBefore John StringAfter"); + $I->fillField("#John", "input"); + $I->dragAndDrop("#John", "Doe"); + $I->conditionalClick("Doe", "#John", true); + $I->amOnUrl("John.html"); + $I->searchAndMultiSelectOption("#selector", ["John", "Doe"]); + $I->fillField("#selector", "StringBefore ".msq("uniqueData")."John StringAfter"); + $I->fillField("#".msq("uniqueData")."John", "input"); + $I->dragAndDrop("#".msq("uniqueData")."John", msq("uniqueData")."John"); + $I->conditionalClick(msq("uniqueData")."John", "#".msq("uniqueData")."John", true); + $I->amOnUrl(msq("uniqueData")."John.html"); + $I->searchAndMultiSelectOption("#selector", [msq("uniqueData")."John", "Doe"]); + $I->fillField("#selector", "StringBefore Doe".msq("uniqueData")." StringAfter"); + $I->fillField("#Doe".msq("uniqueData"), "input"); + $I->dragAndDrop("#Doe".msq("uniqueData"), "Doe".msq("uniqueData")); + $I->conditionalClick("Doe".msq("uniqueData"), "#Doe".msq("uniqueData"), true); + $I->amOnUrl("Doe".msq("uniqueData").".html"); + $I->searchAndMultiSelectOption("#selector", ["John", "Doe".msq("uniqueData")]); + $I->searchAndMultiSelectOption("#selector", [msq("uniqueData")."John", "Doe".msq("uniqueData")]); + } +} diff --git a/dev/tests/verification/Resources/PageReplacementCest.txt b/dev/tests/verification/Resources/PageReplacementCest.txt new file mode 100644 index 000000000..b71d113dd --- /dev/null +++ b/dev/tests/verification/Resources/PageReplacementCest.txt @@ -0,0 +1,41 @@ +amGoingTo("create entity that has the mergeKey: datakey"); + $simpleData = DataObjectHandler::getInstance()->getObject("simpleData"); + $datakey = new DataPersistenceHandler($simpleData); + $datakey->createEntity(); + $I->amOnPage("/page.html"); + $I->amOnPage("/StringLiteral/page.html"); + $I->amOnPage("/John/page.html"); + $I->amOnPage("/" . $datakey->getCreatedDataByName('firstname') . "/page.html"); + $I->amOnPage("/StringLiteral1/StringLiteral2.html"); + $I->amOnPage("/John/StringLiteral2.html"); + $I->amOnPage("/John/" . $datakey->getCreatedDataByName('firstname') . ".html"); + $I->amOnPage("/" . $datakey->getCreatedDataByName('firstname') . "/StringLiteral2.html"); + } +} diff --git a/dev/tests/verification/Resources/PersistedReplacementCest.txt b/dev/tests/verification/Resources/PersistedReplacementCest.txt index d52b74930..4b41e0fbb 100644 --- a/dev/tests/verification/Resources/PersistedReplacementCest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementCest.txt @@ -38,34 +38,17 @@ class PersistedReplacementCest */ public function PersistedReplacementTest(AcceptanceTester $I) { - $I->amGoingTo("create entity that has the mergeKey: testScopeData"); - $ReplacementPerson = DataObjectHandler::getInstance()->getObject("ReplacementPerson"); - $testScopeData = new DataPersistenceHandler($ReplacementPerson); - $testScopeData->createEntity(); - $I->amGoingTo("create entity that has the mergeKey: uniqueData"); - $UniquePerson = DataObjectHandler::getInstance()->getObject("UniquePerson"); - $uniqueData = new DataPersistenceHandler($UniquePerson); - $uniqueData->createEntity(); - $I->amOnPage("/success/success2.html"); - $I->amOnPage($testScopeData->getCreatedDataByName('firstname') . ".html"); - $I->amOnPage($this->createData1->getCreatedDataByName('firstname') . ".html"); - $I->amOnPage("/" . $testScopeData->getCreatedDataByName('firstname') . "/" . $testScopeData->getCreatedDataByName('lastname') . ".html"); - $I->amOnPage("/" . $this->createData1->getCreatedDataByName('firstname') . "/" . $this->createData1->getCreatedDataByName('lastname') . ".html"); - $I->click("#element ." . $testScopeData->getCreatedDataByName('firstname')); - $I->click("#" . $testScopeData->getCreatedDataByName('firstname') . " .success"); - $I->click("#John-Doe ." . $testScopeData->getCreatedDataByName('lastname')); - $I->click("#" . $testScopeData->getCreatedDataByName('firstname') . " ." . $testScopeData->getCreatedDataByName('lastname')); - $I->click("#" . $this->createData1->getCreatedDataByName('firstname') . " ." . $this->createData1->getCreatedDataByName('lastname')); - $I->fillField("#sample", "Hello " . $testScopeData->getCreatedDataByName('firstname') . " " . $testScopeData->getCreatedDataByName('lastname')); - $I->fillField("#sample", "Hello " . $this->createData1->getCreatedDataByName('firstname') . " " . $this->createData1->getCreatedDataByName('lastname')); - $I->searchAndMultiSelectOption("#selector", [$testScopeData->getCreatedDataByName('lastname')]); - $I->searchAndMultiSelectOption("#selector", [$this->createData1->getCreatedDataByName('lastname')]); - $I->amOnPage($uniqueData->getCreatedDataByName('firstname') . ".html"); - $I->amOnPage("/" . $uniqueData->getCreatedDataByName('firstname') . "/" . $uniqueData->getCreatedDataByName('lastname') . ".html"); - $I->click("#element ." . $uniqueData->getCreatedDataByName('firstname')); - $I->click("#" . $uniqueData->getCreatedDataByName('firstname') . " .success"); - $I->click("#" . $uniqueData->getCreatedDataByName('firstname')); - $I->dragAndDrop($uniqueData->getCreatedDataByName('firstname'), $uniqueData->getCreatedDataByName('firstname')); - $I->dragAndDrop("#element ." . $uniqueData->getCreatedDataByName('firstname'), "#" . $uniqueData->getCreatedDataByName('firstname') . " .success"); + $I->amGoingTo("create entity that has the mergeKey: createdData"); + $simpleData = DataObjectHandler::getInstance()->getObject("simpleData"); + $createdData = new DataPersistenceHandler($simpleData); + $createdData->createEntity(); + $I->fillField("#selector", "StringBefore " . $createdData->getCreatedDataByName('firstname') . " StringAfter"); + $I->fillField("#" . $createdData->getCreatedDataByName('firstname'), "input"); + $I->dragAndDrop("#" . $createdData->getCreatedDataByName('firstname'), $createdData->getCreatedDataByName('lastname')); + $I->conditionalClick($createdData->getCreatedDataByName('lastname'), "#" . $createdData->getCreatedDataByName('firstname'), true); + $I->amOnUrl($createdData->getCreatedDataByName('firstname') . ".html"); + $I->searchAndMultiSelectOption("#selector", [$createdData->getCreatedDataByName('firstname') . "", "" . $createdData->getCreatedDataByName('lastname')]); + $I->fillField("#selector", "John " . $createdData->getCreatedDataByName('firstname') . " stringLiteral"); + $I->searchAndMultiSelectOption("#selector", [$createdData->getCreatedDataByName('firstname') . "", "John", "stringLiteral"]); } } diff --git a/dev/tests/verification/Resources/SectionReplacementCest.txt b/dev/tests/verification/Resources/SectionReplacementCest.txt new file mode 100644 index 000000000..fe5795ab5 --- /dev/null +++ b/dev/tests/verification/Resources/SectionReplacementCest.txt @@ -0,0 +1,59 @@ +click("#element"); + $I->click("#foo"); + $I->waitForPageLoad(30); + $I->click("#element .stringLiteral"); + $I->click("#stringLiteral1 .stringLiteral2"); + $I->click("#stringLiteral1-stringLiteral2 .stringLiteral3"); + $I->click("#stringLiteral1-stringLiteral2 .stringLiteral1 [stringLiteral3]"); + $I->click("#element .John"); + $I->click("#John .Doe"); + $I->click("#John-Doe .Tiberius"); + $I->click("#John-Doe .John [Tiberius]"); + $I->click("#element .".msq("uniqueData")."John"); + $I->click("#".msq("uniqueData")."John .stringLiteral2"); + $I->click("#".msq("uniqueData")."John-stringLiteral2 .stringLiteral3"); + $I->click("#".msq("uniqueData")."John-stringLiteral2 ."); + $I->click("#element .Doe".msq("uniqueData")); + $I->click("#Doe".msq("uniqueData")." .stringLiteral2"); + $I->click("#Doe".msq("uniqueData")."-stringLiteral2 .stringLiteral3"); + $I->click("#Doe".msq("uniqueData")."-stringLiteral2 .Doe"); + $I->amGoingTo("create entity that has the mergeKey: createdData"); + $simpleData = DataObjectHandler::getInstance()->getObject("simpleData"); + $createdData = new DataPersistenceHandler($simpleData); + $createdData->createEntity(); + $I->click("#element ." . $createdData->getCreatedDataByName('firstname')); + $I->click("#" . $createdData->getCreatedDataByName('firstname') . " .stringLiteral2"); + $I->click("#" . $createdData->getCreatedDataByName('firstname') . "-stringLiteral2 .stringLiteral3"); + $I->click("#" . $createdData->getCreatedDataByName('firstname') . "-stringLiteral2 ." . $createdData->getCreatedDataByName('firstname') . " [stringLiteral3]"); + $I->click("#stringLiteral1-" . $createdData->getCreatedDataByName('firstname') . " .John"); + $I->click("#stringLiteral1-" . $createdData->getCreatedDataByName('firstname') . " .".msq("uniqueData")."John"); + $I->click("#stringLiteral1-" . $createdData->getCreatedDataByName('firstname') . " .Doe".msq("uniqueData")); + } +} diff --git a/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml b/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml deleted file mode 100644 index 48cff411e..000000000 --- a/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dev/tests/verification/TestModule/Cest/dataReplacementCest.xml b/dev/tests/verification/TestModule/Cest/dataReplacementCest.xml new file mode 100644 index 000000000..1e33dd731 --- /dev/null +++ b/dev/tests/verification/TestModule/Cest/dataReplacementCest.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dev/tests/verification/TestModule/Cest/pageReplacementCest.xml b/dev/tests/verification/TestModule/Cest/pageReplacementCest.xml new file mode 100644 index 000000000..26ad49337 --- /dev/null +++ b/dev/tests/verification/TestModule/Cest/pageReplacementCest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dev/tests/verification/TestModule/Cest/persistedReplacementCest.xml b/dev/tests/verification/TestModule/Cest/persistedReplacementCest.xml new file mode 100644 index 000000000..663c51ef7 --- /dev/null +++ b/dev/tests/verification/TestModule/Cest/persistedReplacementCest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/verification/TestModule/Cest/sectionReplacementCest.xml b/dev/tests/verification/TestModule/Cest/sectionReplacementCest.xml new file mode 100644 index 000000000..ca91fef27 --- /dev/null +++ b/dev/tests/verification/TestModule/Cest/sectionReplacementCest.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dev/tests/verification/TestModule/Data/replacementData.xml b/dev/tests/verification/TestModule/Data/replacementData.xml new file mode 100644 index 000000000..de25aead8 --- /dev/null +++ b/dev/tests/verification/TestModule/Data/replacementData.xml @@ -0,0 +1,21 @@ + + + + + + + John + Doe + Tiberius + + + John + Doe + + diff --git a/dev/tests/verification/TestModule/Page/SamplePage.xml b/dev/tests/verification/TestModule/Page/SamplePage.xml index 02eca33c9..22b85737d 100644 --- a/dev/tests/verification/TestModule/Page/SamplePage.xml +++ b/dev/tests/verification/TestModule/Page/SamplePage.xml @@ -11,4 +11,13 @@
+ +
+ + +
+ + +
+ diff --git a/dev/tests/verification/TestModule/Section/SampleSection.xml b/dev/tests/verification/TestModule/Section/SampleSection.xml index 211af228d..63a525886 100644 --- a/dev/tests/verification/TestModule/Section/SampleSection.xml +++ b/dev/tests/verification/TestModule/Section/SampleSection.xml @@ -9,9 +9,11 @@
+ +
diff --git a/dev/tests/verification/Tests/PersistedReplacementGenerationTest.php b/dev/tests/verification/Tests/PersistedReplacementGenerationTest.php deleted file mode 100644 index b95afc99d..000000000 --- a/dev/tests/verification/Tests/PersistedReplacementGenerationTest.php +++ /dev/null @@ -1,38 +0,0 @@ -getObject(self::PERSISTED_REPLACEMENT_CEST); - $test = TestGenerator::getInstance(null, [$cest]); - $test->createAllCestFiles(); - - $cestFile = $test->getExportDir() . - DIRECTORY_SEPARATOR . - self::PERSISTED_REPLACEMENT_CEST . - ".php"; - - $this->assertTrue(file_exists($cestFile)); - - $this->assertFileEquals( - self::RESOURCES_PATH . DIRECTORY_SEPARATOR . self::PERSISTED_REPLACEMENT_CEST . ".txt", - $cestFile - ); - } -} diff --git a/dev/tests/verification/Tests/ReferenceReplacementGenerationTest.php b/dev/tests/verification/Tests/ReferenceReplacementGenerationTest.php new file mode 100644 index 000000000..572e30985 --- /dev/null +++ b/dev/tests/verification/Tests/ReferenceReplacementGenerationTest.php @@ -0,0 +1,76 @@ +runComparisonTest(self::DATA_REPLACEMENT_CEST); + } + + /** + * Tests replacement of $data.key$ references. + */ + public function testPersistedeferenceReplacementCest() + { + $this->runComparisonTest(self::PERSISTED_REPLACEMENT_CEST); + } + + /** + * Tests replacement of {{page.url}} references. Includes parameterized urls. + */ + public function testPageReferenceReplacementCest() + { + $this->runComparisonTest(self::PAGE_REPLACEMENT_CEST); + } + + /** + * Tests replacement of {{Section.Element}} references. Includes parameterized elements. + */ + public function testSectionReferenceReplacementCest() + { + $this->runComparisonTest(self::SECTION_REPLACEMENT_CEST); + } + + /** + * Instantiates CestObjectHandler and TestGenerator, then compares given cest against flat txt equivalent. + * @param string $cestName + */ + private function runComparisonTest($cestName) + { + $cest = CestObjectHandler::getInstance()->getObject($cestName); + $test = TestGenerator::getInstance(null, [$cest]); + $test->createAllCestFiles(); + + $cestFile = $test->getExportDir() . + DIRECTORY_SEPARATOR . + $cestName . + ".php"; + + $this->assertTrue(file_exists($cestFile)); + + + $this->assertFileEquals( + self::RESOURCES_PATH . DIRECTORY_SEPARATOR . $cestName . ".txt", + $cestFile + ); + } +} diff --git a/etc/di.xml b/etc/di.xml index ad5b0db84..60071a55f 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -208,7 +208,7 @@ createDataKey createDataKey createDataKey - mergeKey + mergeKey *Cest.xml Cest @@ -218,9 +218,9 @@ - mergeKey - mergeKey - mergeKey + mergeKey + mergeKey + mergeKey name name createDataKey diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 9647d0f34..4909f0e83 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -373,6 +373,7 @@ private function findAndReplaceReferences($objectHandler, $inputString) private function matchParameterReferences($reference, $parameters) { preg_match_all('/{{[\w.]+}}/', $reference, $varMatches); + $varMatches[0] = array_unique($varMatches[0]); if (count($varMatches[0]) > count($parameters)) { if (is_array($parameters)) { $parametersGiven = implode(",", $parameters); diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 2108627aa..b318ed4ed 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -451,7 +451,7 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) } if (isset($customActionAttributes['dependentSelector'])) { - $dependentSelector = $this->wrapWithDoubleQuotes($customActionAttributes['dependentSelector']); + $dependentSelector = $this->addUniquenessFunctionCall($customActionAttributes['dependentSelector']); } if (isset($customActionAttributes['visible'])) { From 8a112cd8034ee794c4f05923e755e27cbf328cfa Mon Sep 17 00:00:00 2001 From: Tom Reece Date: Fri, 10 Nov 2017 10:17:32 -0600 Subject: [PATCH 09/29] MQE-421: Create Unit Tests for the object model --- composer.json | 8 +- dev/tests/_bootstrap.php | 8 +- dev/tests/phpunit.xml | 5 +- .../Handlers/DataObjectHandlerTest.php | 96 +++++++++ .../OperationDefinitionObjectHandlerTest.php | 20 ++ .../Objects/EntityDataObjectTest.php | 20 ++ .../Page/Handlers/PageObjectHandlerTest.php | 17 ++ .../Handlers/SectionObjectHandlerTest.php | 17 ++ .../Page/Objects/ElementObjectTest.php | 47 +++++ .../Page/Objects/PageObjectTest.php | 34 ++++ .../Page/Objects/SectionObjectTest.php | 71 +++++++ .../Test/Objects/ActionObjectTest.php | 191 ++++++++++++++++++ .../Test/Util/ActionMergeUtilTest.php | 7 +- .../Test/Objects/ActionObject.php | 14 +- 14 files changed, 544 insertions(+), 11 deletions(-) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Objects/EntityDataObjectTest.php create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/PageObjectTest.php create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php diff --git a/composer.json b/composer.json index 427d08cbe..28ee9c1c6 100755 --- a/composer.json +++ b/composer.json @@ -13,13 +13,19 @@ "require-dev": { "squizlabs/php_codesniffer": "1.5.3", "sebastian/phpcpd": "~3.0", - "brainmaestro/composer-git-hooks": "^2.3" + "brainmaestro/composer-git-hooks": "^2.3", + "codeception/aspect-mock": "^2.0" }, "autoload": { "psr-4": { "Magento\\FunctionalTestingFramework\\": ["src/Magento/FunctionalTestingFramework"] } }, + "autoload-dev": { + "psr-4": { + "tests\\unit\\Magento\\FunctionalTestingFramework\\": ["dev/tests/unit/Magento/FunctionalTestingFramework"] + } + }, "extra": { "hooks": { "pre-push": "bin/copyright-check" diff --git a/dev/tests/_bootstrap.php b/dev/tests/_bootstrap.php index 57721a44e..f2da861f0 100644 --- a/dev/tests/_bootstrap.php +++ b/dev/tests/_bootstrap.php @@ -8,6 +8,13 @@ define('PROJECT_ROOT', dirname(dirname(__DIR__))); require_once PROJECT_ROOT . '/vendor/autoload.php'; +// Set up AspectMock +$kernel = \AspectMock\Kernel::getInstance(); +$kernel->init([ + 'debug' => true, + 'includePaths' => [PROJECT_ROOT . '/src'] +]); + // Load needed framework env params $TEST_ENVS = [ 'MAGENTO_BASE_URL' => 'http://baseurl:8080', @@ -23,7 +30,6 @@ // Add our test module to the whitelist putenv('MODULE_WHITELIST=Magento_TestModule'); - // Define our own set of paths for the tests defined('FW_BP') || define('FW_BP', PROJECT_ROOT); diff --git a/dev/tests/phpunit.xml b/dev/tests/phpunit.xml index 4751e1765..ea9f46865 100644 --- a/dev/tests/phpunit.xml +++ b/dev/tests/phpunit.xml @@ -9,7 +9,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/6.3/phpunit.xsd" convertNoticesToExceptions="false" - bootstrap="_bootstrap.php"> + bootstrap="_bootstrap.php" + backupGlobals="false"> verification @@ -27,4 +28,4 @@ ../../src/Magento/FunctionalTestingFramework/Util - \ No newline at end of file + diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php new file mode 100644 index 000000000..c09e47478 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php @@ -0,0 +1,96 @@ + [ + 'EntityOne' => [ + 'type' => 'testType', + 'data' => [ + 0 => [ + 'key' => 'testKey', + 'value' => 'testValue' + ] + ] + ] + ] + ]; + + /** + * Set up everything required to mock DataObjectHander::getInstance() + * The first call to getInstance() uses these mocks to emulate the parser, initializing internal state + * according to the PARSER_OUTPUT value + */ + public static function setUpBeforeClass() + { + $mockDataProfileSchemaParser = AspectMock::double(DataProfileSchemaParser::class, [ + 'readDataProfiles' => self::PARSER_OUTPUT + ])->make(); + + $mockObjectManager = AspectMock::double(ObjectManager::class, [ + 'create' => $mockDataProfileSchemaParser + ])->make(); + + AspectMock::double(ObjectManagerFactory::class, [ + 'getObjectManager' => $mockObjectManager + ]); + } + + /** + * getAllObjects should contain the expected data object + */ + public function testGetAllObjects() + { + // Call the method under test + + $actual = DataObjectHandler::getInstance()->getAllObjects(); + + // Assert + + $expected = new EntityDataObject('EntityOne', 'testType', ['testkey' => 'testValue'], [], null, []); + $this->assertArrayHasKey('EntityOne', $actual); + $this->assertEquals($expected, $actual['EntityOne']); + } + + /** + * getObject should return the expected data object if it exists + */ + public function testGetObject() + { + // Call the method under test + + $actual = DataObjectHandler::getInstance()->getObject('EntityOne'); + + // Assert + + $expected = new EntityDataObject('EntityOne', 'testType', ['testkey' => 'testValue'], [], null, []); + $this->assertEquals($expected, $actual); + } + + /** + * getObject should return null if the data object does not exist + */ + public function testGetObjectNull() + { + $actual = DataObjectHandler::getInstance()->getObject('h953u789h0g73t521'); // doesnt exist + $this->assertNull($actual); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php new file mode 100644 index 000000000..f08e659eb --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/OperationDefinitionObjectHandlerTest.php @@ -0,0 +1,20 @@ +markTestIncomplete('TODO'); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Objects/EntityDataObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Objects/EntityDataObjectTest.php new file mode 100644 index 000000000..2dcff1eff --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Objects/EntityDataObjectTest.php @@ -0,0 +1,20 @@ +markTestIncomplete('TODO'); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php new file mode 100644 index 000000000..57c4cbe21 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/PageObjectHandlerTest.php @@ -0,0 +1,17 @@ +markTestIncomplete('TODO'); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php new file mode 100644 index 000000000..95cbb12db --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Handlers/SectionObjectHandlerTest.php @@ -0,0 +1,17 @@ +markTestIncomplete('TODO'); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php new file mode 100644 index 000000000..aefef682e --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php @@ -0,0 +1,47 @@ +assertNull($element->getTimeout()); + } + + /** + * Timeout should be cast to an integer + */ + public function testTimeoutNotNull() + { + $element = new ElementObject('name', 'type', 'selector', '15', false); + $timeout = $element->getTimeout(); + $this->assertEquals(15, $timeout); + $this->assertInternalType('int', $timeout); + } + + /** + * Timeout should be 0 when a string is the value + */ + public function testTimeoutCastFromString() + { + $element = new ElementObject('name', 'type', 'selector', 'helloString', true); + $timeout = $element->getTimeout(); + $this->assertEquals(0, $timeout); + $this->assertInternalType('int', $timeout); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/PageObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/PageObjectTest.php new file mode 100644 index 000000000..e83154b19 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/PageObjectTest.php @@ -0,0 +1,34 @@ +assertTrue($page->hasSection('section1')); + } + + /** + * Assert that the page object doesn't have a section + */ + public function testDoesntHaveSection() + { + $page = new PageObject('name', 'urlPath', 'module', ['section1', 'section2'], false); + $this->assertFalse($page->hasSection('section3')); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php new file mode 100644 index 000000000..0caab118b --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php @@ -0,0 +1,71 @@ + $element1, + 'element2' => $element2 + ]; + $section = new SectionObject('test', $elements); + $this->assertTrue($section->hasElement('element1')); + } + + /** + * Assert that the section object doesn't have an element + */ + public function testDoesntHaveElement() { + $element2 = new ElementObject('element2', 'type', '#selector', '42', true); + $elements = [ + 'element2' => $element2 + ]; + $section = new SectionObject('test', $elements); + $this->assertFalse($section->hasElement('element1')); + } + + /** + * Assert that an element object is returned + */ + public function testGetElement() { + $element1 = new ElementObject('element1', 'type', '#selector', '41', false); + $element2 = new ElementObject('element2', 'type', '#selector', '42', true); + $elements = [ + 'element1' => $element1, + 'element2' => $element2 + ]; + $section = new SectionObject('test', $elements); + $gotElement = $section->getElement('element2'); + $this->assertInstanceOf(ElementObject::class, $gotElement); + $this->assertEquals($gotElement, $element2); + } + + /** + * Assert that null is returned if no such element + */ + public function testNullGetElement() { + $element1 = new ElementObject('element1', 'type', '#selector', '41', false); + $elements = [ + 'element1' => $element1 + ]; + $section = new SectionObject('test', $elements); + $this->assertNull($section->getElement('element2')); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php new file mode 100644 index 000000000..1037eb394 --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php @@ -0,0 +1,191 @@ +assertEquals(0, $actionObject->getOrderOffset()); + } + + /** + * The order offset should be 1 when the action is instantiated with 'after' + */ + public function testConstructOrderAfter() + { + $actionObject = new ActionObject('mergeKey', 'type', [], null, 'after'); + $this->assertEquals(1, $actionObject->getOrderOffset()); + } + + /** + * {{Section.element}} should be replaced with #theElementSelector + */ + public function testResolveElementInSelector() + { + // Set up mocks + $actionObject = new ActionObject('merge123', 'fillField', [ + 'selector' => '{{SectionObject.elementObject}}', + 'userInput' => 'Hello world' + ]); + $elementObject = new ElementObject('elementObject', 'button', '#replacementSelector', '42', false); + $sectionObject = new SectionObject('SectionObject', ['elementObject' => $elementObject]); + $instance = AspectMock::double(SectionObjectHandler::class, ['getObject' => $sectionObject]) + ->make(); // bypass the private constructor + AspectMock::double(SectionObjectHandler::class, ['getInstance' => $instance]); + + // Call the method under test + $actionObject->resolveReferences(); + + // Verify + $expected = [ + 'selector' => '#replacementSelector', + 'userInput' => 'Hello world' + ]; + $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); + } + + /** + * {{Section.element(param)}} should be replaced + */ + public function testResolveSelectorWithOneParam() + { + $this->markTestIncomplete('TODO'); + } + + /** + * {{Section.element(param1,param2)}} should be replaced + */ + public function testResolveSelectorWithManyParams() + { + $this->markTestIncomplete('TODO'); + } + + /** + * Timeout property on the ActionObject should be set if the ElementObject has a timeout + */ + public function testTimeoutFromElement() + { + // Set up mocks + $actionObject = new ActionObject('merge123', 'click', [ + 'selector' => '{{SectionObject.elementObject}}' + ]); + $elementObject = new ElementObject('elementObject', 'button', '#replacementSelector', '42', false); + $sectionObject = new SectionObject('SectionObject', ['elementObject' => $elementObject]); + $instance = AspectMock::double(SectionObjectHandler::class, ['getObject' => $sectionObject]) + ->make(); // bypass the private constructor + AspectMock::double(SectionObjectHandler::class, ['getInstance' => $instance]); + + // Call the method under test + $actionObject->resolveReferences(); + + // Verify + $this->assertEquals(42, $actionObject->getTimeout()); + } + + /** + * {{PageObject.url}} should be replaced with someUrl.html + */ + public function testResolveUrl() + { + // Set up mocks + $actionObject = new ActionObject('merge123', 'amOnPage', [ + 'url' => '{{PageObject.url}}' + ]); + $pageObject = new PageObject('PageObject', '/replacement/url.html', 'Test', [], false); + $instance = AspectMock::double(PageObjectHandler::class, ['getObject' => $pageObject]) + ->make(); // bypass the private constructor + AspectMock::double(PageObjectHandler::class, ['getInstance' => $instance]); + + // Call the method under test + $actionObject->resolveReferences(); + + // Verify + $expected = [ + 'url' => '/replacement/url.html' + ]; + $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); + } + + /** + * {{PageObject.url(param)}} should be replaced + */ + public function testResolveUrlWithOneParam() + { + $this->markTestIncomplete('TODO'); + } + + /** + * {{PageObject.url(param1,param2,param3)}} should be replaced + */ + public function testResolveUrlWithManyParams() + { + $this->markTestIncomplete('TODO'); + } + + /** + * {{EntityDataObject.key}} should be replaced with someDataValue + */ + public function testResolveDataInUserInput() + { + // Set up mocks + $actionObject = new ActionObject('merge123', 'fillField', [ + 'selector' => '#selector', + 'userInput' => '{{EntityDataObject.key}}' + ]); + $entityDataObject = new EntityDataObject('EntityDataObject', 'test', [ + 'key' => 'replacementData' + ], [], '', ''); + $instance = AspectMock::double(DataObjectHandler::class, ['getObject' => $entityDataObject]) + ->make(); // bypass the private constructor + AspectMock::double(DataObjectHandler::class, ['getInstance' => $instance]); + + // Call the method under test + $actionObject->resolveReferences(); + + // Verify + $expected = [ + 'selector' => '#selector', + 'userInput' => 'replacementData' + ]; + $this->assertEquals($expected, $actionObject->getCustomActionAttributes()); + } + + /** + * $testScopeData$ (single dollar sign) should be replaced + */ + public function testTestScopeDataResolution() + { + $this->markTestIncomplete('TODO'); + } + + /** + * $$cestScopeData$$ (double dollar sign) should be replaced + */ + public function testCestScopeDataResolution() + { + $this->markTestIncomplete('TODO'); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php index 495f6eff1..00d2c7bb6 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php @@ -101,7 +101,7 @@ public function testResolveActionStepOrdering() */ public function testResolveActionStepSectionData() { - //TODO implement section object mocker and test + $this->markTestIncomplete('TODO'); } /** @@ -109,9 +109,9 @@ public function testResolveActionStepSectionData() * * @return void */ - public function resolveActionStepPageData() + public function testResolveActionStepPageData() { - //TODO implement page object mocker and test + $this->markTestIncomplete('TODO'); } /** @@ -121,6 +121,7 @@ public function resolveActionStepPageData() */ public function testResolveActionStepEntityData() { + $this->markTestSkipped('This test was written using reflection instead of AspectMock. It needs refactored.'); $dataObjectName = 'myObject'; $dataObjectType = 'testObject'; $dataFieldName = 'myfield'; diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 4909f0e83..9b7d9b632 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -22,6 +22,7 @@ class ActionObject const DATA_ENABLED_ATTRIBUTES = ["userInput", "parameterArray"]; const SELECTOR_ENABLED_ATTRIBUTES = ['selector', 'dependentSelector', "selector1", "selector2"]; const MERGE_ACTION_ORDER_AFTER = 'after'; + const MERGE_ACTION_ORDER_BEFORE = 'before'; const ACTION_ATTRIBUTE_URL = 'url'; const ACTION_ATTRIBUTE_SELECTOR = 'selector'; const ACTION_ATTRIBUTE_VARIABLE_REGEX_PARAMETER = '/\(.+\)/'; @@ -83,10 +84,15 @@ class ActionObject * @param string $type * @param array $actionAttributes * @param string|null $linkedAction - * @param int $order + * @param string $order */ - public function __construct($mergeKey, $type, $actionAttributes, $linkedAction = null, $order = 0) - { + public function __construct( + $mergeKey, + $type, + $actionAttributes, + $linkedAction = null, + $order = ActionObject::MERGE_ACTION_ORDER_BEFORE + ) { $this->mergeKey = $mergeKey; $this->type = $type; $this->actionAttributes = $actionAttributes; @@ -351,7 +357,7 @@ private function findAndReplaceReferences($objectHandler, $inputString) throw new TestReferenceException("Could not resolve entity reference " . $inputString); } - //If Page or Section's Element is has parameterized = true attribute, attempt to do parameter replacement. + // If Page or Section's Element has the parameterized = true attribute, attempt to do parameter replacement if ($parameterized) { $parameterList = $this->stripAndReturnParameters($match); $replacement = $this->matchParameterReferences($replacement, $parameterList); From b4ecb1f23114d06c50768e9f40b99383704948a0 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Thu, 9 Nov 2017 13:42:28 -0600 Subject: [PATCH 10/29] MQE-235: added codeception Asserts module functions in framework. --- composer.json | 2 +- .../Resources/BasicFunctionalCest.txt | 44 ++ .../Resources/PersistedReplacementCest.txt | 10 + .../Cest/PersistedReplacementCest.xml | 15 + .../TestModule/Cest/basicFunctionalCest.xml | 45 ++ etc/di.xml | 12 +- .../Test/etc/testSchema.xsd | 518 ++++++++++++++++++ .../Util/TestGenerator.php | 138 ++++- 8 files changed, 776 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 427d08cbe..ba3610ea0 100755 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "keywords": ["magento", "automation", "functional", "testing"], "require": { "php": "~7.0", - "codeception/codeception": "2.2|2.3", + "codeception/codeception": "~2.3.4", "flow/jsonpath": ">0.2", "fzaninotto/faker": "^1.6", "mustache/mustache": "~2.5" diff --git a/dev/tests/verification/Resources/BasicFunctionalCest.txt b/dev/tests/verification/Resources/BasicFunctionalCest.txt index 94bba2310..5b841a3df 100644 --- a/dev/tests/verification/Resources/BasicFunctionalCest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalCest.txt @@ -128,5 +128,49 @@ class BasicFunctionalCest $I->waitForElementVisible(".functionalTestSelector", 30); $I->waitForJS("someJsFunction", 30); $I->waitForText("someInput", 30, ".functionalTestSelector"); + $I->assertArrayHasKey("apple", ['orange' => "2", 'apple' => "1"], "pass"); + $I->assertArrayNotHasKey("kiwi", ['orange' => "2", 'apple' => "1"], "pass"); + $I->assertArraySubset(["1", "2"], ["5", "3", "2", "1"], "pass"); + $I->assertContains("ab", ['item1' => 'a', 'item2' => 'ab'], "pass"); + $I->assertCount("2", ['a', 'b'], "pass"); + $I->assertEmpty("''", "pass"); + $I->assertEmpty("[]", "pass"); + $I->assertEmpty($value1, "pass"); + $I->assertEquals("abc", "abc", "pass"); + $I->assertEquals("2", $value1, "pass"); + $I->assertFalse($value1, "pass"); + $I->assertFileExists("/out.txt", "pass"); + $I->assertFileExists($value1, "pass"); + $I->assertFileNotExists("/out.txt", "pass"); + $I->assertFileNotExists("file", "pass"); + $I->assertGreaterOrEquals("5", "2", "pass"); + $I->assertGreaterThan("5", "2", "pass"); + $I->assertGreaterThanOrEqual("5", "2", "pass"); + $I->assertInstanceOf(User::class, $value1, "pass"); + $I->assertInternalType("string", "xyz", "pass"); + $I->assertInternalType("xyz", "pass"); + $I->assertInternalType($value1, "pass"); + $I->assertIsEmpty($value1, "pass"); + $I->assertLessOrEquals("2", "5", "pass"); + $I->assertLessThan("2", "5", "pass"); + $I->assertLessThanOrEqual("2", "5", "pass"); + $I->assertNotContains("bc", ['item1' => 'a', 'item2' => 'ab'], "pass"); + $I->assertNotContains("bc", "pass"); + $I->assertNotEmpty("[1, 2]", "pass"); + $I->assertNotEmpty($value1, "pass"); + $I->assertNotEquals("2", "5", "pass"); + $I->assertNotInstanceOf("21", "pass"); + $I->assertNotNull("abc", "pass"); + $I->assertNotNull($value1, "pass"); + $I->assertNotRegExp("/foo/", "bar", "pass"); + $I->assertNotSame("log", "tag", "pass"); + $I->assertNull($value1, "pass"); + $I->assertRegExp("/foo/", "foo", "pass"); + $I->assertSame("bar", "bar", "pass"); + $I->assertStringStartsNotWith("a", "banana", "pass"); + $I->assertStringStartsWith("a", "apple", "pass"); + $I->assertTrue("true", "pass"); + $I->expectException(new MyException('exception msg'), function() {$this->doSomethingBad();}); + $I->fail("fail"); } } diff --git a/dev/tests/verification/Resources/PersistedReplacementCest.txt b/dev/tests/verification/Resources/PersistedReplacementCest.txt index d52b74930..3c5e955e4 100644 --- a/dev/tests/verification/Resources/PersistedReplacementCest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementCest.txt @@ -67,5 +67,15 @@ class PersistedReplacementCest $I->click("#" . $uniqueData->getCreatedDataByName('firstname')); $I->dragAndDrop($uniqueData->getCreatedDataByName('firstname'), $uniqueData->getCreatedDataByName('firstname')); $I->dragAndDrop("#element ." . $uniqueData->getCreatedDataByName('firstname'), "#" . $uniqueData->getCreatedDataByName('firstname') . " .success"); + $I->assertStringStartsNotWith("D", $this->createData1->getCreatedDataByName('lastname') . ", " . $this->createData1->getCreatedDataByName('firstname'), "fail"); + $I->assertStringStartsWith("W", $uniqueData->getCreatedDataByName('firstname') . " " . $uniqueData->getCreatedDataByName('lastname'), "pass"); + $I->assertEquals($this->createData1->getCreatedDataByName('lastname'), $this->createData1->getCreatedDataByName('lastname'), "pass"); + $I->assertFileExists("../Data/SampleData.xml", "pass"); + $I->assertArraySubset([$this->createData1->getCreatedDataByName('lastname') . "", "" . $this->createData1->getCreatedDataByName('firstname')], [$this->createData1->getCreatedDataByName('lastname') . "", "" . $this->createData1->getCreatedDataByName('firstname') . "", "1"], "pass"); + $I->assertArraySubset([$uniqueData->getCreatedDataByName('firstname') . "", "" . $uniqueData->getCreatedDataByName('lastname')], [$uniqueData->getCreatedDataByName('firstname') . "", "" . $uniqueData->getCreatedDataByName('lastname') . "", "1"], "pass"); + $I->assertArrayHasKey("lastname", ['lastname' => $this->createData1->getCreatedDataByName('lastname') . "", 'firstname' => "" . $this->createData1->getCreatedDataByName('firstname')], "pass"); + $I->assertArrayHasKey("lastname", ['lastname' => $uniqueData->getCreatedDataByName('lastname') . "", 'firstname' => "" . $uniqueData->getCreatedDataByName('firstname')], "pass"); + $I->fail($uniqueData->getCreatedDataByName('firstname') . " " . $uniqueData->getCreatedDataByName('lastname')); + $I->fail($this->createData1->getCreatedDataByName('firstname') . " " . $this->createData1->getCreatedDataByName('lastname')); } } diff --git a/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml b/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml index 48cff411e..431245a15 100644 --- a/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml +++ b/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml @@ -61,7 +61,22 @@ + + + + + + + + + + + + + + +
diff --git a/dev/tests/verification/TestModule/Cest/basicFunctionalCest.xml b/dev/tests/verification/TestModule/Cest/basicFunctionalCest.xml index 28578bd44..f18b72ff8 100644 --- a/dev/tests/verification/TestModule/Cest/basicFunctionalCest.xml +++ b/dev/tests/verification/TestModule/Cest/basicFunctionalCest.xml @@ -113,6 +113,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/di.xml b/etc/di.xml index ad5b0db84..e85eabe73 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -208,7 +208,7 @@ createDataKey createDataKey createDataKey - mergeKey + mergeKey *Cest.xml Cest @@ -218,9 +218,9 @@ - mergeKey - mergeKey - mergeKey + mergeKey + mergeKey + mergeKey name name createDataKey @@ -284,7 +284,7 @@ name name - mergeKey + mergeKey *ActionGroup.xml ActionGroup @@ -294,7 +294,7 @@ - mergeKey + mergeKey name name diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd index d6cd059b3..fd6bb745b 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd @@ -183,6 +183,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1521,4 +1555,488 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 2108627aa..6d08ec8c1 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -352,6 +352,16 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) $dependentSelector = null; $visible = null; + $assertExpected = null; + $assertExpectedArray = null; + $assertActual = null; + $assertActualArray = null; + $assertMessage = null; + $assertFunction = null; + $assertIsStrict = null; + $assertDelta = null; + $class = null; + if (isset($customActionAttributes['returnVariable'])) { $returnVariable = $customActionAttributes['returnVariable']; } @@ -367,10 +377,25 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) $input = $this->addUniquenessFunctionCall($customActionAttributes['url']); } + if (isset($customActionAttributes['expected'])) { + $assertExpected = $this->addUniquenessFunctionCall($customActionAttributes['expected']); + } + if (isset($customActionAttributes['actual'])) { + $assertActual = $this->addUniquenessFunctionCall($customActionAttributes['actual']); + } + if (isset($customActionAttributes['message'])) { + $assertMessage = $this->addUniquenessFunctionCall($customActionAttributes['message']); + } + if (isset($customActionAttributes['expectedVariable'])) { + $assertExpected = $this->addDollarSign($customActionAttributes['expectedVariable']); + } + if (isset($customActionAttributes['actualVariable'])) { + $assertActual = $this->addDollarSign($customActionAttributes['actualVariable']); + } + if (isset($customActionAttributes['time'])) { $time = $customActionAttributes['time']; } - if (isset($customActionAttributes['timeout'])) { $time = $customActionAttributes['timeout']; } @@ -383,6 +408,22 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) $customActionAttributes['parameterArray'] ) . "]"; } + if (isset($customActionAttributes['expectedArray'])) { + // validate the param array is in the correct format + $this->validateParameterArray($customActionAttributes['expectedArray']); + + $assertExpectedArray = "[" + . $this->addUniquenessToParamArray($customActionAttributes['expectedArray']) + . "]"; + } + if (isset($customActionAttributes['actualArray'])) { + // validate the param array is in the correct format + $this->validateParameterArray($customActionAttributes['actualArray']); + + $assertActualArray = "[" + . $this->addUniquenessToParamArray($customActionAttributes['actualArray']) + . "]"; + } if (isset($customActionAttributes['requiredAction'])) { $requiredAction = $customActionAttributes['requiredAction']; @@ -414,6 +455,10 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) $function = $customActionAttributes['function']; } + if (isset($customActionAttributes['class'])) { + $class = $customActionAttributes['class']; + } + if (isset($customActionAttributes['html'])) { $html = $customActionAttributes['html']; } @@ -883,6 +928,95 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) case "conditionalClick": $testSteps .= $this->wrapFunctionCall($actor, $actionName, $selector, $dependentSelector, $visible); break; + case "assertEquals": + case "assertGreaterOrEquals": + case "assertGreaterThan": + case "assertGreaterThanOrEqual": + case "assertInternalType": + case "assertLessOrEquals": + case "assertLessThan": + case "assertLessThanOrEqual": + case "assertNotEquals": + + case "assertNotRegExp": + case "assertNotSame": + case "assertRegExp": + case "assertSame": + case "assertStringStartsNotWith": + case "assertStringStartsWith": + $testSteps .= $this->wrapFunctionCall( + $actor, + $actionName, + $assertExpected, + $assertActual, + $assertMessage, + $assertDelta + ); + break; + case "assertInstanceOf": + case "assertNotInstanceOf": + $testSteps .= $this->wrapFunctionCall( + $actor, + $actionName, + $class, + $assertActual, + $assertMessage + ); + break; + case "assertArrayHasKey": + case "assertArrayNotHasKey": + case "assertCount": + case "assertContains": + case "assertNotContains": + $testSteps .= $this->wrapFunctionCall( + $actor, + $actionName, + $assertExpected, + $assertActualArray, + $assertMessage + ); + break; + case "assertEmpty": + case "assertFalse": + case "assertFileExists": + case "assertFileNotExists": + case "assertIsEmpty": + case "assertNotEmpty": + case "assertNotNull": + case "assertNull": + case "assertTrue": + $testSteps .= $this->wrapFunctionCall( + $actor, + $actionName, + $assertActual, + $assertMessage + ); + break; + case "assertArraySubset": + $testSteps .= $this->wrapFunctionCall( + $actor, + $actionName, + $assertExpectedArray, + $assertActualArray, + $assertIsStrict, + $assertMessage + ); + break; + case "expectException": + $testSteps .= $this->wrapFunctionCall( + $actor, + $actionName, + $class, + $function + ); + break; + case "fail": + $testSteps .= $this->wrapFunctionCall( + $actor, + $actionName, + $assertMessage + ); + break; default: if ($returnVariable) { $testSteps .= $this->wrapFunctionCallWithReturnValue( @@ -1020,6 +1154,7 @@ private function stripAndSplitReference($reference, $delimiter) * Creates a PHP string for the _before/_after methods if the Test contains an or block. * @param array $hookObjects * @return string + * @throws TestReferenceException */ private function generateHooksPhp($hookObjects) { @@ -1168,6 +1303,7 @@ private function generateTestAnnotationsPhp($testAnnotationsObject) * Concatenates the Test Annotations PHP and Test PHP for a single Test. * @param array $testsObject * @return string + * @throws TestReferenceException */ private function generateTestsPhp($testsObject) { From ff6d257eea1ea3605ca816352825f27c95010f7e Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Fri, 10 Nov 2017 11:20:19 -0600 Subject: [PATCH 11/29] MQE-336: [Generator] Add support for Codeception "Locator" selectors - Added locatorFunction attribute to elements and ElementObject - Changed ActionObject to look for selector, then locatorFunction when trying to resolve element references. - TestGenerator fixes to add double quotes to locatorFunction arguments, necessary for good output. - Verification test fixes and additions. --- .../Resources/ActionGroupFunctionalCest.txt | 1 + .../Resources/BasicFunctionalCest.txt | 1 + .../Resources/DataReplacementCest.txt | 1 + .../Resources/LocatorFunctionCest.txt | 46 ++++++++++++++++ .../Resources/MergeFunctionalCest.txt | 1 + .../Resources/PageReplacementCest.txt | 1 + .../Resources/ParameterArrayCest.txt | 1 + .../Resources/PersistedReplacementCest.txt | 1 + .../Resources/SectionReplacementCest.txt | 1 + .../TestModule/Cest/LocatorFunctionCest.xml | 32 +++++++++++ .../Section/LocatorFunctionSection.xml | 19 +++++++ .../Tests/LocatorFunctionGenerationTest.php | 38 +++++++++++++ .../Page/Handlers/SectionObjectHandler.php | 5 +- .../Page/Objects/ElementObject.php | 32 ++++++++++- .../Page/etc/SectionObject.xsd | 11 +++- .../Test/Objects/ActionObject.php | 4 +- .../Util/TestGenerator.php | 54 +++++++++++++++++++ 17 files changed, 244 insertions(+), 5 deletions(-) create mode 100644 dev/tests/verification/Resources/LocatorFunctionCest.txt create mode 100644 dev/tests/verification/TestModule/Cest/LocatorFunctionCest.xml create mode 100644 dev/tests/verification/TestModule/Section/LocatorFunctionSection.xml create mode 100644 dev/tests/verification/Tests/LocatorFunctionGenerationTest.php diff --git a/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt b/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt index a2b40ac98..9a5344a7c 100644 --- a/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt +++ b/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt @@ -5,6 +5,7 @@ use Magento\FunctionalTestingFramework\AcceptanceTester; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Persist\DataPersistenceHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; use Yandex\Allure\Adapter\Annotation\Title; diff --git a/dev/tests/verification/Resources/BasicFunctionalCest.txt b/dev/tests/verification/Resources/BasicFunctionalCest.txt index 94bba2310..c59bf9926 100644 --- a/dev/tests/verification/Resources/BasicFunctionalCest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalCest.txt @@ -5,6 +5,7 @@ use Magento\FunctionalTestingFramework\AcceptanceTester; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Persist\DataPersistenceHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; use Yandex\Allure\Adapter\Annotation\Title; diff --git a/dev/tests/verification/Resources/DataReplacementCest.txt b/dev/tests/verification/Resources/DataReplacementCest.txt index 60f847bb4..f0cb52be1 100644 --- a/dev/tests/verification/Resources/DataReplacementCest.txt +++ b/dev/tests/verification/Resources/DataReplacementCest.txt @@ -5,6 +5,7 @@ use Magento\FunctionalTestingFramework\AcceptanceTester; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Persist\DataPersistenceHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; use Yandex\Allure\Adapter\Annotation\Title; diff --git a/dev/tests/verification/Resources/LocatorFunctionCest.txt b/dev/tests/verification/Resources/LocatorFunctionCest.txt new file mode 100644 index 000000000..6ee99c63e --- /dev/null +++ b/dev/tests/verification/Resources/LocatorFunctionCest.txt @@ -0,0 +1,46 @@ +amGoingTo("create entity that has the mergeKey: data"); + $ReplacementPerson = DataObjectHandler::getInstance()->getObject("ReplacementPerson"); + $data = new DataPersistenceHandler($ReplacementPerson); + $data->createEntity(); + $I->click(Locator::contains("'label'", "'Name'")); + $I->click(Locator::contains("'label'", "'Name'")); + $I->click(Locator::find("'img'", ['title' => 'diagram'])); + $I->click(Locator::contains("string", "'Name'")); + $I->click(Locator::contains("John", "'Name'")); + $I->click(Locator::contains($data->getCreatedDataByName('key') . "", "'Name'")); + $I->click(Locator::contains("string1", "string2")); + $I->click(Locator::contains("John", "Doe")); + $I->click(Locator::contains($data->getCreatedDataByName('key1') . "", "" . $data->getCreatedDataByName('key2'))); + $I->click(Locator::contains("string1", "John")); + $I->click(Locator::contains("string1", "" . $data->getCreatedDataByName('key1'))); + $I->click(Locator::contains("John", "" . $data->getCreatedDataByName('key1'))); + } +} diff --git a/dev/tests/verification/Resources/MergeFunctionalCest.txt b/dev/tests/verification/Resources/MergeFunctionalCest.txt index 9645490bb..aa6a75a43 100644 --- a/dev/tests/verification/Resources/MergeFunctionalCest.txt +++ b/dev/tests/verification/Resources/MergeFunctionalCest.txt @@ -5,6 +5,7 @@ use Magento\FunctionalTestingFramework\AcceptanceTester; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Persist\DataPersistenceHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; use Yandex\Allure\Adapter\Annotation\Title; diff --git a/dev/tests/verification/Resources/PageReplacementCest.txt b/dev/tests/verification/Resources/PageReplacementCest.txt index b71d113dd..bfb459b5b 100644 --- a/dev/tests/verification/Resources/PageReplacementCest.txt +++ b/dev/tests/verification/Resources/PageReplacementCest.txt @@ -5,6 +5,7 @@ use Magento\FunctionalTestingFramework\AcceptanceTester; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Persist\DataPersistenceHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; use Yandex\Allure\Adapter\Annotation\Title; diff --git a/dev/tests/verification/Resources/ParameterArrayCest.txt b/dev/tests/verification/Resources/ParameterArrayCest.txt index 1e4ae4b39..496e5670b 100644 --- a/dev/tests/verification/Resources/ParameterArrayCest.txt +++ b/dev/tests/verification/Resources/ParameterArrayCest.txt @@ -5,6 +5,7 @@ use Magento\FunctionalTestingFramework\AcceptanceTester; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Persist\DataPersistenceHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; use Yandex\Allure\Adapter\Annotation\Title; diff --git a/dev/tests/verification/Resources/PersistedReplacementCest.txt b/dev/tests/verification/Resources/PersistedReplacementCest.txt index 4b41e0fbb..c0c0d0a7e 100644 --- a/dev/tests/verification/Resources/PersistedReplacementCest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementCest.txt @@ -5,6 +5,7 @@ use Magento\FunctionalTestingFramework\AcceptanceTester; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Persist\DataPersistenceHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; use Yandex\Allure\Adapter\Annotation\Title; diff --git a/dev/tests/verification/Resources/SectionReplacementCest.txt b/dev/tests/verification/Resources/SectionReplacementCest.txt index fe5795ab5..333f5ac4f 100644 --- a/dev/tests/verification/Resources/SectionReplacementCest.txt +++ b/dev/tests/verification/Resources/SectionReplacementCest.txt @@ -5,6 +5,7 @@ use Magento\FunctionalTestingFramework\AcceptanceTester; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Persist\DataPersistenceHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use \Codeception\Util\Locator; use Yandex\Allure\Adapter\Annotation\Features; use Yandex\Allure\Adapter\Annotation\Stories; use Yandex\Allure\Adapter\Annotation\Title; diff --git a/dev/tests/verification/TestModule/Cest/LocatorFunctionCest.xml b/dev/tests/verification/TestModule/Cest/LocatorFunctionCest.xml new file mode 100644 index 000000000..497320d15 --- /dev/null +++ b/dev/tests/verification/TestModule/Cest/LocatorFunctionCest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dev/tests/verification/TestModule/Section/LocatorFunctionSection.xml b/dev/tests/verification/TestModule/Section/LocatorFunctionSection.xml new file mode 100644 index 000000000..1acb939e1 --- /dev/null +++ b/dev/tests/verification/TestModule/Section/LocatorFunctionSection.xml @@ -0,0 +1,19 @@ + + + + +
+ + + + + + +
+
diff --git a/dev/tests/verification/Tests/LocatorFunctionGenerationTest.php b/dev/tests/verification/Tests/LocatorFunctionGenerationTest.php new file mode 100644 index 000000000..e7d9648b1 --- /dev/null +++ b/dev/tests/verification/Tests/LocatorFunctionGenerationTest.php @@ -0,0 +1,38 @@ +getObject(self::LOCATOR_FUNCTION_CEST); + $test = TestGenerator::getInstance(null, [$cest]); + $test->createAllCestFiles(); + + $cestFile = $test->getExportDir() . + DIRECTORY_SEPARATOR . + self::LOCATOR_FUNCTION_CEST . + ".php"; + + $this->assertTrue(file_exists($cestFile)); + + $this->assertFileEquals( + self::RESOURCES_PATH . DIRECTORY_SEPARATOR . self::LOCATOR_FUNCTION_CEST . ".txt", + $cestFile + ); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php index 8bd5863a4..a39db4c69 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Page/Handlers/SectionObjectHandler.php @@ -21,6 +21,7 @@ class SectionObjectHandler implements ObjectHandlerInterface const SUB_TYPE = 'element'; const ELEMENT_TYPE_ATTR = 'type'; const ELEMENT_SELECTOR_ATTR = 'selector'; + const ELEMENT_LOCATOR_FUNC_ATTR = 'locatorFunction'; const ELEMENT_TIMEOUT_ATTR = 'timeout'; const ELEMENT_PARAMETERIZED = 'parameterized'; @@ -109,7 +110,8 @@ private function initSectionObjects() $elements = []; foreach ($sectionData[SectionObjectHandler::SUB_TYPE] as $elementName => $elementData) { $elementType = $elementData[SectionObjectHandler::ELEMENT_TYPE_ATTR]; - $elementSelector = $elementData[SectionObjectHandler::ELEMENT_SELECTOR_ATTR]; + $elementSelector = $elementData[SectionObjectHandler::ELEMENT_SELECTOR_ATTR] ?? null; + $elementLocatorFunc = $elementData[SectionObjectHandler::ELEMENT_LOCATOR_FUNC_ATTR] ?? null; $elementTimeout = $elementData[SectionObjectHandler::ELEMENT_TIMEOUT_ATTR] ?? null; $elementParameterized = $elementData[SectionObjectHandler::ELEMENT_PARAMETERIZED] ?? false; @@ -117,6 +119,7 @@ private function initSectionObjects() $elementName, $elementType, $elementSelector, + $elementLocatorFunc, $elementTimeout, $elementParameterized ); diff --git a/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php b/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php index b55911b61..f0bc1f404 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php +++ b/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php @@ -5,6 +5,8 @@ */ namespace Magento\FunctionalTestingFramework\Page\Objects; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; + /** * Class ElementObject */ @@ -33,6 +35,13 @@ class ElementObject */ private $selector; + /** + * Section element locatorFunction + * + * @var string + */ + private $locatorFunction; + /** * Section element timeout * @@ -52,14 +61,25 @@ class ElementObject * @param string $name * @param string $type * @param string $selector + * @param string $locatorFunction * @param string $timeout * @param bool $parameterized + * @throws XmlException */ - public function __construct($name, $type, $selector, $timeout, $parameterized) + public function __construct($name, $type, $selector, $locatorFunction, $timeout, $parameterized) { + //Elements cannot have both a selector and a locatorFunction defined + if ($selector != null && $locatorFunction != null) { + throw new XmlException("Element '{$name}' cannot have both a selector and a locatorFunction."); + } + $this->name = $name; $this->type = $type; $this->selector = $selector; + $this->locatorFunction = $locatorFunction; + if (strpos($locatorFunction, "Locator::") === false) { + $this->locatorFunction = "Locator::" . $locatorFunction; + } $this->timeout = $timeout; $this->parameterized = $parameterized; } @@ -94,6 +114,16 @@ public function getSelector() return $this->selector; } + /** + * Getter for the locatorFunction of an element + * + * @return string + */ + public function getLocatorFunction() + { + return $this->locatorFunction; + } + /** * Returns an integer representing an element's timeout * diff --git a/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd b/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd index 4fdeba173..3c95a5ffc 100644 --- a/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd +++ b/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd @@ -64,10 +64,17 @@ - + - Selector of the element. + Selector of the element. Optional due to being able to use either this or locatorFunction. + + + + + + + LocatorFunction of an element, substitute for a selector. diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php index 4909f0e83..028d2884f 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionObject.php @@ -323,7 +323,9 @@ private function findAndReplaceReferences($objectHandler, $inputString) throw new TestReferenceException("Could not resolve entity reference " . $inputString); } $parameterized = $obj->getElement($objField)->isParameterized(); - $replacement = $obj->getElement($objField)->getSelector(); + // If no Selector is defined, assume element has LocatorFunction + $replacement = $obj->getElement($objField)->getSelector() ?: + $obj->getElement($objField)->getLocatorFunction(); $this->timeout = $obj->getElement($objField)->getTimeout(); break; case (get_class($obj) == EntityDataObject::class): diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index b318ed4ed..e2ea66463 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -213,6 +213,7 @@ private function generateUseStatementsPhp() $useStatementsPhp .= "use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler;\n"; $useStatementsPhp .= "use Magento\FunctionalTestingFramework\DataGenerator\Persist\DataPersistenceHandler;\n"; $useStatementsPhp .= "use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject;\n"; + $useStatementsPhp .= "use \Codeception\Util\Locator;\n"; $allureStatements = [ "Yandex\Allure\Adapter\Annotation\Features;", @@ -392,14 +393,17 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) $selector = $customActionAttributes['selectorArray']; } elseif (isset($customActionAttributes['selector'])) { $selector = $this->addUniquenessFunctionCall($customActionAttributes['selector']); + $selector = $this->resolveLocatorFunctionInAttribute($selector); } if (isset($customActionAttributes['selector1'])) { $selector1 = $this->addUniquenessFunctionCall($customActionAttributes['selector1']); + $selector1 = $this->resolveLocatorFunctionInAttribute($selector1); } if (isset($customActionAttributes['selector2'])) { $selector2 = $this->addUniquenessFunctionCall($customActionAttributes['selector2']); + $selector2 = $this->resolveLocatorFunctionInAttribute($selector2); } if (isset($customActionAttributes['x'])) { @@ -902,6 +906,20 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) return $testSteps; } + /** + * Resolves Locator:: in given $attribute if it is found. + * @param string $attribute + * @return string + */ + private function resolveLocatorFunctionInAttribute($attribute) + { + if (strpos($attribute, "Locator::") !== false) { + $attribute = $this->stripWrappedQuotes($attribute); + $attribute = $this->wrapFunctionArgsWithQuotes("/Locator::[\w]+\(([\s\S]+)\)/", $attribute); + } + return $attribute; + } + /** * Resolves replacement of $input$ and $$input$$ in given function, recursing and replacing individual arguments * Also determines if each argument requires any quote replacement. @@ -1004,6 +1022,42 @@ private function processQuoteBreaks($match, $argument, $replacement) return $outputArg; } + /** + * Wraps all args inside function give with double quotes. Uses regex to locate arguments of function + * @param string $functionRegex + * @param string $input + * @return string + */ + private function wrapFunctionArgsWithQuotes($functionRegex, $input) + { + $output = $input; + preg_match_all($functionRegex, $input, $matches); + + //If no Arguments were passed in + if (!isset($matches[1][0])) { + return $input; + } + + $allArguments = explode(',', $matches[1][0]); + foreach ($allArguments as $argument) { + $argument = trim($argument); + + if ($argument[0] == "[") { + $replacement = "[" . $this->addUniquenessToParamArray($argument) . "]"; + } elseif (is_numeric($argument)) { + $replacement = $argument; + } else { + $replacement = $this->addUniquenessFunctionCall($argument); + } + + //Replace only first occurrence of argument with "argument" + $pos = strpos($output, $argument); + $output = substr_replace($output, $replacement, $pos, strlen($argument)); + } + + return $output; + } + /** * Performs str_replace on variable reference, dependent on delimiter and returns exploded array. * @param string $reference From 91cc4344b4a98402e57c3ea4afa9c6c33e188f13 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 1 Nov 2017 15:40:33 -0500 Subject: [PATCH 12/29] MQE-448: created a utility script to generate mftf metadata from magenta swagger specification. --- composer.json | 3 +- .../{ => FormData}/MetadataGenUtil.php | 2 +- .../_generateMetadataFile.php} | 4 +- .../{ => FormData}/input.yml.sample | 0 .../{ => FormData}/views/operation.mustache | 2 +- .../views/partials/field.mustache | 0 .../views/partials/object.mustache | 0 .../Swagger/MetadataGenerator.php | 533 ++++++++++++++++++ .../Swagger/_generateMetadataFile.php | 10 + .../MetadataGenerator/Swagger/autoload.php | 17 + .../MetadataGenerator/Swagger/magento.json | 1 + .../Swagger/views/definition.mustache | 14 + .../Swagger/views/operation.mustache | 16 + .../Swagger/views/partials/array1.mustache | 12 + .../Swagger/views/partials/array2.mustache | 12 + .../Swagger/views/partials/array3.mustache | 12 + .../Swagger/views/partials/field.mustache | 9 + .../Swagger/views/partials/field2.mustache | 9 + .../Swagger/views/partials/param.mustache | 9 + .../Swagger/views/partials/value.mustache | 9 + 20 files changed, 669 insertions(+), 5 deletions(-) rename src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/{ => FormData}/MetadataGenUtil.php (99%) rename src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/{_generateMetadtataFile.php => FormData/_generateMetadataFile.php} (85%) rename src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/{ => FormData}/input.yml.sample (100%) rename src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/{ => FormData}/views/operation.mustache (83%) rename src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/{ => FormData}/views/partials/field.mustache (100%) rename src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/{ => FormData}/views/partials/object.mustache (100%) create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/MetadataGenerator.php create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/_generateMetadataFile.php create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/autoload.php create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/magento.json create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/definition.mustache create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/operation.mustache create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array1.mustache create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array2.mustache create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array3.mustache create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field.mustache create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field2.mustache create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/param.mustache create mode 100644 src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/value.mustache diff --git a/composer.json b/composer.json index 427d08cbe..b576844ea 100755 --- a/composer.json +++ b/composer.json @@ -8,7 +8,8 @@ "codeception/codeception": "2.2|2.3", "flow/jsonpath": ">0.2", "fzaninotto/faker": "^1.6", - "mustache/mustache": "~2.5" + "mustache/mustache": "~2.5", + "epfremme/swagger-php": "^2.0" }, "require-dev": { "squizlabs/php_codesniffer": "1.5.3", diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/MetadataGenUtil.php b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/MetadataGenUtil.php similarity index 99% rename from src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/MetadataGenUtil.php rename to src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/MetadataGenUtil.php index 2015a2554..d510e5d39 100644 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/MetadataGenUtil.php +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/MetadataGenUtil.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\FunctionalTestingFramework\Util\MetadataGenerator; +namespace Magento\FunctionalTestingFramework\Util\MetadataGenerator\FormData; use Mustache_Engine; use Mustache_Loader_FilesystemLoader; diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/_generateMetadtataFile.php b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/_generateMetadataFile.php similarity index 85% rename from src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/_generateMetadtataFile.php rename to src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/_generateMetadataFile.php index 25aa7ee19..fce54be41 100644 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/_generateMetadtataFile.php +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/_generateMetadataFile.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -require_once '../../../../../vendor/autoload.php'; +require_once '../../../../../../vendor/autoload.php'; const INPUT_TXT_FILE = 'input.yml'; @@ -12,7 +12,7 @@ $inputCfg = \Symfony\Component\Yaml\Yaml::parse(file_get_contents(INPUT_TXT_FILE)); // create new MetadataGenUtil Object -$metadataGenUtil = new Magento\FunctionalTestingFramework\Util\MetadataGenerator\MetadataGenUtil( +$metadataGenUtil = new Magento\FunctionalTestingFramework\Util\MetadataGenerator\FormData\MetadataGenUtil( $inputCfg['operationName'], $inputCfg['operationDataType'], $inputCfg['operationUrl'], diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/input.yml.sample b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/input.yml.sample similarity index 100% rename from src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/input.yml.sample rename to src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/input.yml.sample diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/operation.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/operation.mustache similarity index 83% rename from src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/operation.mustache rename to src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/operation.mustache index f3ba9ddfe..ee96c4175 100644 --- a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/operation.mustache +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/operation.mustache @@ -6,7 +6,7 @@ */ --> - + {{>object}} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/partials/field.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/partials/field.mustache similarity index 100% rename from src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/partials/field.mustache rename to src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/partials/field.mustache diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/partials/object.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/partials/object.mustache similarity index 100% rename from src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/views/partials/object.mustache rename to src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/FormData/views/partials/object.mustache diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/MetadataGenerator.php b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/MetadataGenerator.php new file mode 100644 index 000000000..64c981fe1 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/MetadataGenerator.php @@ -0,0 +1,533 @@ + 'create', + 'DELETE' => 'delete', + 'PUT' => 'update', + 'GET' => 'get', + ]; + + /** + * Build and initialize generator. + */ + public function __construct() + { + self::buildSwaggerSpec(); + $this->initMustacheTemplates(); + } + + /** + * Parse swagger spec from input json file. + * TODO: read swagger spec from magento server. + * + * @return void + */ + public function generateMetadataFromSwagger() + { + $paths = self::$swagger->getPaths(); + + foreach ($paths->getIterator() as $pathKey => $path) { + $operations = $path->getOperations(); + foreach ($operations->getIterator() as $operationKey => $operation) { + $this->renderOperation($operation, $pathKey, $operationKey); + } + } + + $definitions = self::$swagger->getDefinitions(); + foreach ($definitions->getIterator() as $defKey => $definition) { + $this->renderDefinition($defKey, $definition); + } + } + + /** + * Render swagger operations. + * + * @param Operation $operation + * @param string $path + * @param string $method + * @return void + */ + private function renderOperation($operation, $path, $method) + { + $operationArray = []; + $this->pathParams = ''; + $this->params = []; + $this->fields = []; + $operationMethod = strtoupper($method); + $operationDataType = ucfirst($operation->getOperationId()); + + $operationArray[self::TEMPLATE_VAR_OP_NAME] = self::$methodMapping[$operationMethod] . $operationDataType; + $operationArray[self::TEMPLATE_VAR_OP_DATATYPE] = $operationDataType; + $operationArray[self::TEMPLATE_VAR_OP_METHOD] = $operationMethod; + $operationArray[self::TEMPLATE_VAR_OP_AUTH] = self::AUTH; + $operationArray[self::TEMPLATE_VAR_OP_TYPE] = self::$methodMapping[$operationMethod]; + $operationArray[self::TEMPLATE_VAR_OP_URL] = $path; + + $params = $operation->getParameters(); + if (!empty($params)) { + $this->parseParams($params, $path); + $operationArray[self::TEMPLATE_VAR_OP_FIELD] = $this->fields; + $operationArray[self::TEMPLATE_VAR_OP_PARAM] = $this->params; + } + + if (!empty($this->pathParams)) { + $operationArray[self::TEMPLATE_VAR_OP_URL] .= $this->pathParams; + } + + $this->generateMetaDataFile( + self::OUTPUT_DIR, + $operationDataType, + 'operation', + $operationArray + ); + } + + /** + * Render swagger definitions. + * + * @param string $defKey + * @param ObjectSchema|ArraySchema $definition + * @return void + */ + private function renderDefinition($defKey, $definition) + { + $operationArray = []; + $this->fields = []; + + $operationArray[self::TEMPLATE_VAR_OP_NAME] = $defKey; + $operationArray[self::TEMPLATE_VAR_OP_DATATYPE] = $defKey; + $operationArray[self::TEMPLATE_VAR_OP_TYPE] = self::TEMPLATE_VAR_DEF_TYPE; + + if ($definition instanceof ObjectSchema) { + $properties = $definition->getProperties(); + if (!empty($properties)) { + $dataField = []; + $dataArray = []; + foreach ($properties->getIterator() as $propertyKey => $property) { + if ($property instanceof ArraySchema) { + $dataArray[] = $this->parseSchema($property, $propertyKey, 1, 1); + } else { + $dataField[] = $this->parseSchema($property, $propertyKey, 0, 1); + } + } + if (!empty($dataField)) { + $operationArray[self::TEMPLATE_VAR_OP_FIELD] = $dataField; + } + if (!empty($dataArray)) { + foreach ($dataArray as $array) { + $operationArray[self::TEMPLATE_VAR_OP_ARRAY.'1'][] = $array[self::TEMPLATE_VAR_OP_ARRAY.'1']; + } + } + } + } elseif ($definition instanceof ArraySchema) { + $operationArray = array_merge($operationArray, $this->parseSchema($definition, $defKey, 1, 1)); + } + + $this->generateMetaDataFile( + self::OUTPUT_DIR2, + $defKey, + 'definition', + $operationArray + ); + } + + /** + * Parse schema and return an array that will be consumed by mustache template engine. + * + * @param SchemaInterface $schema + * @param string $name + * @param bool $forArray + * @param integer $depth + * @return array + */ + private function parseSchema($schema, $name, $forArray, $depth) + { + $data = []; + + if ($schema instanceof RefSchema) { + $ref = $schema->getRef(); + preg_match(self::REF_REGEX, $ref, $matches); + if (count($matches) == 2) { + if (!$forArray) { + $data[self::TEMPLATE_VAR_FIELD_NAME] = $name; + $data[self::TEMPLATE_VAR_FIELD_TYPE] = $matches[1]; + } else { + $data[self::TEMPLATE_VAR_VALUES][] = [self::TEMPLATE_VAR_VALUE => $matches[1]]; + } + } + } elseif ($schema instanceof ArraySchema) { + $values = []; + $items = $schema->getItems(); + $data[self::TEMPLATE_VAR_OP_ARRAY.$depth][self::TEMPLATE_VAR_ARRAY_KEY] = $name; + if ($items instanceof ArrayCollection) { + foreach ($items->getIterator() as $itemKey => $item) { + $values[] = $this->parseSchema($item, $itemKey, 1, $depth+1); + } + $data[self::TEMPLATE_VAR_VALUES] = $values; + $data[self::TEMPLATE_VAR_OP_ARRAY.$depth] = $data; + } else { + $data[self::TEMPLATE_VAR_OP_ARRAY.$depth] = array_merge( + $data[self::TEMPLATE_VAR_OP_ARRAY.$depth], + $this->parseSchema($items, $name, 1, $depth+1) + ); + } + } else { + if (method_exists($schema, 'getType')) { + if (!$forArray) { + $data[self::TEMPLATE_VAR_FIELD_NAME] = $name; + $data[self::TEMPLATE_VAR_FIELD_TYPE] = $schema->getType(); + } else { + $data[self::TEMPLATE_VAR_VALUES][] = [self::TEMPLATE_VAR_VALUE => $schema->getType()]; + } + } + } + return $data; + } + + /** + * Parse params for an operation. + * + * @param ArrayCollection $params + * @param string $path + * @return void + */ + private function parseParams($params, $path) + { + foreach ($params->getIterator() as $paramKey => $param) { + if (empty($param)) { + continue; + } + + $paramIn = $param->getIn(); + if ($paramIn == 'body') { + $this->setBodyParams($param); + } elseif ($paramIn == 'path') { + $this->setPathParams($param, $path); + } elseif ($paramIn == 'query') { + $this->setQueryParams($param); + } + } + } + + /** + * Set body params for an operation. + * + * @param BodyParameter $param + * @return void + */ + private function setBodyParams($param) + { + $this->fields = []; + $required = []; + + $paramSchema = $param->getSchema(); + $paramSchemaRequired = $paramSchema->getRequired(); + if (!empty($paramSchemaRequired)) { + foreach ($paramSchemaRequired as $i => $key) { + $required[] = $key; + } + } + $paramSchemaProperties = $paramSchema->getProperties(); + foreach ($paramSchemaProperties->getIterator() as $paramPropertyKey => $paramSchemaProperty) { + $field = []; + $field[self::TEMPLATE_VAR_FIELD_NAME] = $paramPropertyKey; + $field[self::TEMPLATE_VAR_FIELD_TYPE] = $paramSchemaProperty->getType(); + if ($field[self::TEMPLATE_VAR_FIELD_TYPE] == 'ref') { + preg_match(self::REF_REGEX, $paramSchemaProperty->getRef(), $matches); + if (count($matches) == 2) { + $field[self::TEMPLATE_VAR_FIELD_TYPE] = $matches[1]; + } + } + if (in_array($paramPropertyKey, $required)) { + $field[self::TEMPLATE_VAR_FIELD_IS_REQUIRED] = 'true'; + } else { + $field[self::TEMPLATE_VAR_FIELD_IS_REQUIRED] = 'false'; + } + $this->fields[] = $field; + } + } + + /** + * Set path params for an operation. + * + * @param AbstractTypedParameter $param + * @param string $path + * @return void + */ + private function setPathParams($param, $path) + { + $pathParamStr = '{' . $param->getName() . '}'; + if (strpos($path, $pathParamStr) === false) { + $this->pathParams .= '/' . $pathParamStr; + } + } + + /** + * Set query params for an operation. + * + * @param AbstractTypedParameter $param + * @return void + */ + private function setQueryParams($param) + { + $query = []; + $query[self::TEMPLATE_VAR_PARAM_NAME] = $param->getName(); + $query[self::TEMPLATE_VAR_PARAM_TYPE] = $param->getType(); + + $this->params[] = $query; + } + + /** + * Build swagger spec from factory. + * + * @return void + */ + private static function buildSwaggerSpec() + { + $factory = new SwaggerFactory(); + self::$swagger = $factory->build(self::INPUT_TXT_FILE); + } + + /** + * Function which initializes mustache templates for file generation. + * + * @return void + */ + private function initMustacheTemplates() + { + $this->mustache_engine = new Mustache_Engine( + ['loader' => new Mustache_Loader_FilesystemLoader("views"), + 'partials_loader' => new Mustache_Loader_FilesystemLoader( + "views" . DIRECTORY_SEPARATOR . "partials" + )] + ); + } + + /** + * Render template and generate a metadata file. + * + * @param string $relativeDir + * @param string $fileName + * @param string $template + * @param array $data + * @return void + */ + private function generateMetaDataFile($relativeDir, $fileName, $template, $data) + { + $this->filepath = $relativeDir . DIRECTORY_SEPARATOR . $fileName . "-meta.xml"; + $result = $this->mustache_engine->render($template, $data); + $this->cleanAndCreateOutputDir(); + file_put_contents( + $this->filepath, + $result + ); + } + + /** + * Function which cleans any previously created fileand creates the _output dir. + * + * @return void + */ + private function cleanAndCreateOutputDir() + { + if (!file_exists(self::OUTPUT_DIR)) { + mkdir(self::OUTPUT_DIR); + } + + if (!file_exists(self::OUTPUT_DIR2)) { + mkdir(self::OUTPUT_DIR2); + } + + if (file_exists($this->filepath)) { + unlink($this->filepath); + } + } + /* + private static function debugData() { + $paramsExample = ['params' => + [ + 'paramName' => 'name', + 'paramType' => 'type' + ], + [ + 'paramName' => 'name', + 'paramType' => 'type' + ], + [ + 'paramName' => 'name', + 'paramType' => 'type' + ], + ]; + $fieldsExample = ['fields' => + [ + 'fieldName' => 'name', + 'fieldType' => 'type', + 'isRequired' => true, + ], + [ + 'fieldName' => 'name', + 'fieldType' => 'type', + 'isRequired' => true, + ], + [ + 'fieldName' => 'name', + 'fieldType' => 'type', + 'isRequired' => true, + ], + ]; + $arraysExample = ['arrays1' => + [ + 'arrayKey' => 'someKey', + 'values' => [ + 'type1', + 'type2', + ], + 'arrays2' => [ + 'arrayKey' => 'otherKey', + 'values' => [ + 'type3', + 'type4', + ], + 'arrays3' => [ + 'arrayKey' => 'anotherKey', + 'values' => [ + 'type5', + 'type6', + ], + ], + ], + ], + [ + 'arrayKey' => 'someKey', + 'values' => [ + [ + 'value' => 'type1', + ], + [ + 'value' => 'type2', + ], + ], + 'arrays2' => [ + 'arrayKey' => 'otherKey', + 'values' => [ + [ + 'value' => 'type3', + ], + [ + 'value' => 'type4', + ], + ], + 'arrays3' => [ + 'arrayKey' => 'anotherKey', + 'values' => [ + [ + 'value' => 'type5', + ], + [ + 'value' => 'type6', + ], + ], + ], + ], + ], + ]; + } + */ +} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/_generateMetadataFile.php b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/_generateMetadataFile.php new file mode 100644 index 000000000..c759b045e --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/_generateMetadataFile.php @@ -0,0 +1,10 @@ +generateMetadataFromSwagger(); diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/autoload.php b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/autoload.php new file mode 100644 index 000000000..e7108d0f4 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/autoload.php @@ -0,0 +1,17 @@ + value pairs for select)","items":{"$ref":"#/definitions/customer-data-option-interface"}},"frontend_class":{"type":"string","description":"Class which is used to display the attribute on frontend."},"user_defined":{"type":"boolean","description":"Current attribute has been defined by a user."},"sort_order":{"type":"integer","description":"Attributes sort order."},"frontend_label":{"type":"string","description":"Label which supposed to be displayed on frontend."},"note":{"type":"string","description":"The note attribute for the element."},"system":{"type":"boolean","description":"This is a system attribute."},"backend_type":{"type":"string","description":"Backend type."},"is_used_in_grid":{"type":"boolean","description":"It is used in customer grid"},"is_visible_in_grid":{"type":"boolean","description":"It is visible in customer grid"},"is_filterable_in_grid":{"type":"boolean","description":"It is filterable in customer grid"},"is_searchable_in_grid":{"type":"boolean","description":"It is searchable in customer grid"},"attribute_code":{"type":"string","description":"Code of the attribute."}},"required":["frontend_input","input_filter","store_label","validation_rules","multiline_count","visible","required","data_model","options","frontend_class","user_defined","sort_order","frontend_label","note","system","backend_type","attribute_code"]},"customer-data-validation-rule-interface":{"type":"object","description":"Validation rule interface.","properties":{"name":{"type":"string","description":"Validation rule name"},"value":{"type":"string","description":"Validation rule value"}},"required":["name","value"]},"customer-data-option-interface":{"type":"object","description":"Option interface.","properties":{"label":{"type":"string","description":"Option label"},"value":{"type":"string","description":"Option value"},"options":{"type":"array","description":"Nested options","items":{"$ref":"#/definitions/customer-data-option-interface"}}},"required":["label"]},"customer-data-customer-interface":{"type":"object","description":"Customer interface.","properties":{"id":{"type":"integer","description":"Customer id"},"group_id":{"type":"integer","description":"Group id"},"default_billing":{"type":"string","description":"Default billing address id"},"default_shipping":{"type":"string","description":"Default shipping address id"},"confirmation":{"type":"string","description":"Confirmation"},"created_at":{"type":"string","description":"Created at time"},"updated_at":{"type":"string","description":"Updated at time"},"created_in":{"type":"string","description":"Created in area"},"dob":{"type":"string","description":"Date of birth"},"email":{"type":"string","description":"Email address"},"firstname":{"type":"string","description":"First name"},"lastname":{"type":"string","description":"Last name"},"middlename":{"type":"string","description":"Middle name"},"prefix":{"type":"string","description":"Prefix"},"suffix":{"type":"string","description":"Suffix"},"gender":{"type":"integer","description":"Gender"},"store_id":{"type":"integer","description":"Store id"},"taxvat":{"type":"string","description":"Tax Vat"},"website_id":{"type":"integer","description":"Website id"},"addresses":{"type":"array","description":"Customer addresses.","items":{"$ref":"#/definitions/customer-data-address-interface"}},"disable_auto_group_change":{"type":"integer","description":"Disable auto group change flag."},"extension_attributes":{"$ref":"#/definitions/customer-data-customer-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["email","firstname","lastname"]},"customer-data-address-interface":{"type":"object","description":"Customer address interface.","properties":{"id":{"type":"integer","description":"ID"},"customer_id":{"type":"integer","description":"Customer ID"},"region":{"$ref":"#/definitions/customer-data-region-interface"},"region_id":{"type":"integer","description":"Region ID"},"country_id":{"type":"string","description":"Country code in ISO_3166-2 format"},"street":{"type":"array","description":"Street","items":{"type":"string"}},"company":{"type":"string","description":"Company"},"telephone":{"type":"string","description":"Telephone number"},"fax":{"type":"string","description":"Fax number"},"postcode":{"type":"string","description":"Postcode"},"city":{"type":"string","description":"City name"},"firstname":{"type":"string","description":"First name"},"lastname":{"type":"string","description":"Last name"},"middlename":{"type":"string","description":"Middle name"},"prefix":{"type":"string","description":"Prefix"},"suffix":{"type":"string","description":"Suffix"},"vat_id":{"type":"string","description":"Vat id"},"default_shipping":{"type":"boolean","description":"If this address is default shipping address."},"default_billing":{"type":"boolean","description":"If this address is default billing address"},"extension_attributes":{"$ref":"#/definitions/customer-data-address-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}}},"customer-data-region-interface":{"type":"object","description":"Customer address region interface.","properties":{"region_code":{"type":"string","description":"Region code"},"region":{"type":"string","description":"Region"},"region_id":{"type":"integer","description":"Region id"},"extension_attributes":{"$ref":"#/definitions/customer-data-region-extension-interface"}},"required":["region_code","region","region_id"]},"customer-data-region-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Customer\\Api\\Data\\RegionInterface"},"customer-data-address-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Customer\\Api\\Data\\AddressInterface"},"framework-attribute-interface":{"type":"object","description":"Interface for custom attribute value.","properties":{"attribute_code":{"type":"string","description":"Attribute code"},"value":{"type":"string","description":"Attribute value"}},"required":["attribute_code","value"]},"customer-data-customer-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Customer\\Api\\Data\\CustomerInterface","properties":{"is_subscribed":{"type":"boolean"},"extension_attribute":{"$ref":"#/definitions/test-module-default-hydrator-data-extension-attribute-interface"}}},"test-module-default-hydrator-data-extension-attribute-interface":{"type":"object","description":"","properties":{"id":{"type":"integer","description":"ID"},"customer_id":{"type":"integer","description":"Customer ID"},"value":{"type":"string","description":"Value"}}},"customer-data-customer-search-results-interface":{"type":"object","description":"Interface for customer search results.","properties":{"items":{"type":"array","description":"Customers list.","items":{"$ref":"#/definitions/customer-data-customer-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"customer-data-validation-results-interface":{"type":"object","description":"Validation results interface.","properties":{"valid":{"type":"boolean","description":"If the provided data is valid."},"messages":{"type":"array","description":"Error messages as array in case of validation failure, else return empty array.","items":{"type":"string"}}},"required":["valid","messages"]},"cms-data-page-interface":{"type":"object","description":"CMS page interface.","properties":{"id":{"type":"integer","description":"ID"},"identifier":{"type":"string","description":"Identifier"},"title":{"type":"string","description":"Title"},"page_layout":{"type":"string","description":"Page layout"},"meta_title":{"type":"string","description":"Meta title"},"meta_keywords":{"type":"string","description":"Meta keywords"},"meta_description":{"type":"string","description":"Meta description"},"content_heading":{"type":"string","description":"Content heading"},"content":{"type":"string","description":"Content"},"creation_time":{"type":"string","description":"Creation time"},"update_time":{"type":"string","description":"Update time"},"sort_order":{"type":"string","description":"Sort order"},"layout_update_xml":{"type":"string","description":"Layout update xml"},"custom_theme":{"type":"string","description":"Custom theme"},"custom_root_template":{"type":"string","description":"Custom root template"},"custom_layout_update_xml":{"type":"string","description":"Custom layout update xml"},"custom_theme_from":{"type":"string","description":"Custom theme from"},"custom_theme_to":{"type":"string","description":"Custom theme to"},"active":{"type":"boolean","description":"Active"}},"required":["identifier"]},"cms-data-page-search-results-interface":{"type":"object","description":"Interface for cms page search results.","properties":{"items":{"type":"array","description":"Pages list.","items":{"$ref":"#/definitions/cms-data-page-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"cms-data-block-interface":{"type":"object","description":"CMS block interface.","properties":{"id":{"type":"integer","description":"ID"},"identifier":{"type":"string","description":"Identifier"},"title":{"type":"string","description":"Title"},"content":{"type":"string","description":"Content"},"creation_time":{"type":"string","description":"Creation time"},"update_time":{"type":"string","description":"Update time"},"active":{"type":"boolean","description":"Active"}},"required":["identifier"]},"cms-data-block-search-results-interface":{"type":"object","description":"Interface for cms block search results.","properties":{"items":{"type":"array","description":"Blocks list.","items":{"$ref":"#/definitions/cms-data-block-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"catalog-data-product-interface":{"type":"object","description":"","properties":{"id":{"type":"integer","description":"Id"},"sku":{"type":"string","description":"Sku"},"name":{"type":"string","description":"Name"},"attribute_set_id":{"type":"integer","description":"Attribute set id"},"price":{"type":"number","description":"Price"},"status":{"type":"integer","description":"Status"},"visibility":{"type":"integer","description":"Visibility"},"type_id":{"type":"string","description":"Type id"},"created_at":{"type":"string","description":"Created date"},"updated_at":{"type":"string","description":"Updated date"},"weight":{"type":"number","description":"Weight"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-extension-interface"},"product_links":{"type":"array","description":"Product links info","items":{"$ref":"#/definitions/catalog-data-product-link-interface"}},"options":{"type":"array","description":"List of product options","items":{"$ref":"#/definitions/catalog-data-product-custom-option-interface"}},"media_gallery_entries":{"type":"array","description":"Media gallery entries","items":{"$ref":"#/definitions/catalog-data-product-attribute-media-gallery-entry-interface"}},"tier_prices":{"type":"array","description":"List of product tier prices","items":{"$ref":"#/definitions/catalog-data-product-tier-price-interface"}},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["sku"]},"catalog-data-product-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductInterface","properties":{"website_ids":{"type":"array","items":{"type":"integer"}},"category_links":{"type":"array","items":{"$ref":"#/definitions/catalog-data-category-link-interface"}},"stock_item":{"$ref":"#/definitions/catalog-inventory-data-stock-item-interface"},"bundle_product_options":{"type":"array","items":{"$ref":"#/definitions/bundle-data-option-interface"}},"downloadable_product_links":{"type":"array","items":{"$ref":"#/definitions/downloadable-data-link-interface"}},"downloadable_product_samples":{"type":"array","items":{"$ref":"#/definitions/downloadable-data-sample-interface"}},"giftcard_amounts":{"type":"array","items":{"$ref":"#/definitions/gift-card-data-giftcard-amount-interface"}},"configurable_product_options":{"type":"array","items":{"$ref":"#/definitions/configurable-product-data-option-interface"}},"configurable_product_links":{"type":"array","items":{"type":"integer"}}}},"catalog-data-category-link-interface":{"type":"object","description":"","properties":{"position":{"type":"integer"},"category_id":{"type":"string","description":"Category id"},"extension_attributes":{"$ref":"#/definitions/catalog-data-category-link-extension-interface"}},"required":["category_id"]},"catalog-data-category-link-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\CategoryLinkInterface"},"catalog-inventory-data-stock-item-interface":{"type":"object","description":"Interface StockItem","properties":{"item_id":{"type":"integer"},"product_id":{"type":"integer"},"stock_id":{"type":"integer","description":"Stock identifier"},"qty":{"type":"number"},"is_in_stock":{"type":"boolean","description":"Stock Availability"},"is_qty_decimal":{"type":"boolean"},"show_default_notification_message":{"type":"boolean"},"use_config_min_qty":{"type":"boolean"},"min_qty":{"type":"number","description":"Minimal quantity available for item status in stock"},"use_config_min_sale_qty":{"type":"integer"},"min_sale_qty":{"type":"number","description":"Minimum Qty Allowed in Shopping Cart or NULL when there is no limitation"},"use_config_max_sale_qty":{"type":"boolean"},"max_sale_qty":{"type":"number","description":"Maximum Qty Allowed in Shopping Cart data wrapper"},"use_config_backorders":{"type":"boolean"},"backorders":{"type":"integer","description":"Backorders status"},"use_config_notify_stock_qty":{"type":"boolean"},"notify_stock_qty":{"type":"number","description":"Notify for Quantity Below data wrapper"},"use_config_qty_increments":{"type":"boolean"},"qty_increments":{"type":"number","description":"Quantity Increments data wrapper"},"use_config_enable_qty_inc":{"type":"boolean"},"enable_qty_increments":{"type":"boolean","description":"Whether Quantity Increments is enabled"},"use_config_manage_stock":{"type":"boolean"},"manage_stock":{"type":"boolean","description":"Can Manage Stock"},"low_stock_date":{"type":"string"},"is_decimal_divided":{"type":"boolean"},"stock_status_changed_auto":{"type":"integer"},"extension_attributes":{"$ref":"#/definitions/catalog-inventory-data-stock-item-extension-interface"}},"required":["qty","is_in_stock","is_qty_decimal","show_default_notification_message","use_config_min_qty","min_qty","use_config_min_sale_qty","min_sale_qty","use_config_max_sale_qty","max_sale_qty","use_config_backorders","backorders","use_config_notify_stock_qty","notify_stock_qty","use_config_qty_increments","qty_increments","use_config_enable_qty_inc","enable_qty_increments","use_config_manage_stock","manage_stock","low_stock_date","is_decimal_divided","stock_status_changed_auto"]},"catalog-inventory-data-stock-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\CatalogInventory\\Api\\Data\\StockItemInterface"},"bundle-data-option-interface":{"type":"object","description":"Interface OptionInterface","properties":{"option_id":{"type":"integer","description":"Option id"},"title":{"type":"string","description":"Option title"},"required":{"type":"boolean","description":"Is required option"},"type":{"type":"string","description":"Input type"},"position":{"type":"integer","description":"Option position"},"sku":{"type":"string","description":"Product sku"},"product_links":{"type":"array","description":"Product links","items":{"$ref":"#/definitions/bundle-data-link-interface"}},"extension_attributes":{"$ref":"#/definitions/bundle-data-option-extension-interface"}}},"bundle-data-link-interface":{"type":"object","description":"Interface LinkInterface","properties":{"id":{"type":"string","description":"The identifier"},"sku":{"type":"string","description":"Linked product sku"},"option_id":{"type":"integer","description":"Option id"},"qty":{"type":"number","description":"Qty"},"position":{"type":"integer","description":"Position"},"is_default":{"type":"boolean","description":"Is default"},"price":{"type":"number","description":"Price"},"price_type":{"type":"integer","description":"Price type"},"can_change_quantity":{"type":"integer","description":"Whether quantity could be changed"},"extension_attributes":{"$ref":"#/definitions/bundle-data-link-extension-interface"}},"required":["is_default","price","price_type"]},"bundle-data-link-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Bundle\\Api\\Data\\LinkInterface"},"bundle-data-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Bundle\\Api\\Data\\OptionInterface"},"downloadable-data-link-interface":{"type":"object","description":"","properties":{"id":{"type":"integer","description":"Sample(or link) id"},"title":{"type":"string"},"sort_order":{"type":"integer"},"is_shareable":{"type":"integer","description":"Shareable status"},"price":{"type":"number","description":"Price"},"number_of_downloads":{"type":"integer","description":"Of downloads per user"},"link_type":{"type":"string"},"link_file":{"type":"string","description":"relative file path"},"link_file_content":{"$ref":"#/definitions/downloadable-data-file-content-interface"},"link_url":{"type":"string","description":"Link url or null when type is 'file'"},"sample_type":{"type":"string"},"sample_file":{"type":"string","description":"relative file path"},"sample_file_content":{"$ref":"#/definitions/downloadable-data-file-content-interface"},"sample_url":{"type":"string","description":"file URL"},"extension_attributes":{"$ref":"#/definitions/downloadable-data-link-extension-interface"}},"required":["sort_order","is_shareable","price","link_type","sample_type"]},"downloadable-data-file-content-interface":{"type":"object","description":"","properties":{"file_data":{"type":"string","description":"Data (base64 encoded content)"},"name":{"type":"string","description":"File name"},"extension_attributes":{"$ref":"#/definitions/downloadable-data-file-content-extension-interface"}},"required":["file_data","name"]},"downloadable-data-file-content-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Downloadable\\Api\\Data\\File\\ContentInterface"},"downloadable-data-link-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Downloadable\\Api\\Data\\LinkInterface"},"downloadable-data-sample-interface":{"type":"object","description":"","properties":{"id":{"type":"integer","description":"Sample(or link) id"},"title":{"type":"string","description":"Title"},"sort_order":{"type":"integer","description":"Order index for sample"},"sample_type":{"type":"string"},"sample_file":{"type":"string","description":"relative file path"},"sample_file_content":{"$ref":"#/definitions/downloadable-data-file-content-interface"},"sample_url":{"type":"string","description":"file URL"},"extension_attributes":{"$ref":"#/definitions/downloadable-data-sample-extension-interface"}},"required":["title","sort_order","sample_type"]},"downloadable-data-sample-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Downloadable\\Api\\Data\\SampleInterface"},"gift-card-data-giftcard-amount-interface":{"type":"object","description":"Interface GiftcardAmountInterface: this interface is used to serialize and deserialize EAV attribute giftcard_amounts","properties":{"attribute_id":{"type":"integer"},"website_id":{"type":"integer"},"value":{"type":"number"},"website_value":{"type":"number"},"extension_attributes":{"$ref":"#/definitions/gift-card-data-giftcard-amount-extension-interface"}},"required":["attribute_id","website_id","value","website_value"]},"gift-card-data-giftcard-amount-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\GiftCard\\Api\\Data\\GiftcardAmountInterface"},"configurable-product-data-option-interface":{"type":"object","description":"Interface OptionInterface","properties":{"id":{"type":"integer"},"attribute_id":{"type":"string"},"label":{"type":"string"},"position":{"type":"integer"},"is_use_default":{"type":"boolean"},"values":{"type":"array","items":{"$ref":"#/definitions/configurable-product-data-option-value-interface"}},"extension_attributes":{"$ref":"#/definitions/configurable-product-data-option-extension-interface"},"product_id":{"type":"integer"}}},"configurable-product-data-option-value-interface":{"type":"object","description":"Interface OptionValueInterface","properties":{"value_index":{"type":"integer"},"extension_attributes":{"$ref":"#/definitions/configurable-product-data-option-value-extension-interface"}},"required":["value_index"]},"configurable-product-data-option-value-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\ConfigurableProduct\\Api\\Data\\OptionValueInterface"},"configurable-product-data-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\ConfigurableProduct\\Api\\Data\\OptionInterface"},"catalog-data-product-link-interface":{"type":"object","description":"","properties":{"sku":{"type":"string","description":"SKU"},"link_type":{"type":"string","description":"Link type"},"linked_product_sku":{"type":"string","description":"Linked product sku"},"linked_product_type":{"type":"string","description":"Linked product type (simple, virtual, etc)"},"position":{"type":"integer","description":"Linked item position"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-link-extension-interface"}},"required":["sku","link_type","linked_product_sku","linked_product_type","position"]},"catalog-data-product-link-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductLinkInterface","properties":{"qty":{"type":"number"}}},"catalog-data-product-custom-option-interface":{"type":"object","description":"","properties":{"product_sku":{"type":"string","description":"Product SKU"},"option_id":{"type":"integer","description":"Option id"},"title":{"type":"string","description":"Option title"},"type":{"type":"string","description":"Option type"},"sort_order":{"type":"integer","description":"Sort order"},"is_require":{"type":"boolean","description":"Is require"},"price":{"type":"number","description":"Price"},"price_type":{"type":"string","description":"Price type"},"sku":{"type":"string","description":"Sku"},"file_extension":{"type":"string"},"max_characters":{"type":"integer"},"image_size_x":{"type":"integer"},"image_size_y":{"type":"integer"},"values":{"type":"array","items":{"$ref":"#/definitions/catalog-data-product-custom-option-values-interface"}},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-custom-option-extension-interface"}},"required":["product_sku","title","type","sort_order","is_require"]},"catalog-data-product-custom-option-values-interface":{"type":"object","description":"","properties":{"title":{"type":"string","description":"Option title"},"sort_order":{"type":"integer","description":"Sort order"},"price":{"type":"number","description":"Price"},"price_type":{"type":"string","description":"Price type"},"sku":{"type":"string","description":"Sku"},"option_type_id":{"type":"integer","description":"Option type id"}},"required":["title","sort_order","price","price_type"]},"catalog-data-product-custom-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductCustomOptionInterface"},"catalog-data-product-attribute-media-gallery-entry-interface":{"type":"object","description":"","properties":{"id":{"type":"integer","description":"Gallery entry ID"},"media_type":{"type":"string","description":"Media type"},"label":{"type":"string","description":"Gallery entry alternative text"},"position":{"type":"integer","description":"Gallery entry position (sort order)"},"disabled":{"type":"boolean","description":"If gallery entry is hidden from product page"},"types":{"type":"array","description":"Gallery entry image types (thumbnail, image, small_image etc)","items":{"type":"string"}},"file":{"type":"string","description":"File path"},"content":{"$ref":"#/definitions/framework-data-image-content-interface"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-attribute-media-gallery-entry-extension-interface"}},"required":["media_type","label","position","disabled","types"]},"framework-data-image-content-interface":{"type":"object","description":"Image Content data interface","properties":{"base64_encoded_data":{"type":"string","description":"Media data (base64 encoded content)"},"type":{"type":"string","description":"MIME type"},"name":{"type":"string","description":"Image name"}},"required":["base64_encoded_data","type","name"]},"catalog-data-product-attribute-media-gallery-entry-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductAttributeMediaGalleryEntryInterface","properties":{"video_content":{"$ref":"#/definitions/framework-data-video-content-interface"}}},"framework-data-video-content-interface":{"type":"object","description":"Video Content data interface","properties":{"media_type":{"type":"string","description":"MIME type"},"video_provider":{"type":"string","description":"Provider"},"video_url":{"type":"string","description":"Video URL"},"video_title":{"type":"string","description":"Title"},"video_description":{"type":"string","description":"Video Description"},"video_metadata":{"type":"string","description":"Metadata"}},"required":["media_type","video_provider","video_url","video_title","video_description","video_metadata"]},"catalog-data-product-tier-price-interface":{"type":"object","description":"","properties":{"customer_group_id":{"type":"integer","description":"Customer group id"},"qty":{"type":"number","description":"Tier qty"},"value":{"type":"number","description":"Price value"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-tier-price-extension-interface"}},"required":["customer_group_id","qty","value"]},"catalog-data-product-tier-price-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductTierPriceInterface","properties":{"percentage_value":{"type":"number"},"website_id":{"type":"integer"}}},"catalog-data-product-search-results-interface":{"type":"object","description":"","properties":{"items":{"type":"array","description":"Attributes list.","items":{"$ref":"#/definitions/catalog-data-product-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"catalog-data-product-attribute-type-interface":{"type":"object","description":"","properties":{"value":{"type":"string","description":"Value"},"label":{"type":"string","description":"Type label"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-attribute-type-extension-interface"}},"required":["value","label"]},"catalog-data-product-attribute-type-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductAttributeTypeInterface"},"catalog-data-product-attribute-interface":{"type":"object","description":"","properties":{"is_wysiwyg_enabled":{"type":"boolean","description":"WYSIWYG flag"},"is_html_allowed_on_front":{"type":"boolean","description":"The HTML tags are allowed on the frontend"},"used_for_sort_by":{"type":"boolean","description":"It is used for sorting in product listing"},"is_filterable":{"type":"boolean","description":"It used in layered navigation"},"is_filterable_in_search":{"type":"boolean","description":"It is used in search results layered navigation"},"is_used_in_grid":{"type":"boolean","description":"It is used in catalog product grid"},"is_visible_in_grid":{"type":"boolean","description":"It is visible in catalog product grid"},"is_filterable_in_grid":{"type":"boolean","description":"It is filterable in catalog product grid"},"position":{"type":"integer","description":"Position"},"apply_to":{"type":"array","description":"Apply to value for the element","items":{"type":"string"}},"is_searchable":{"type":"string","description":"The attribute can be used in Quick Search"},"is_visible_in_advanced_search":{"type":"string","description":"The attribute can be used in Advanced Search"},"is_comparable":{"type":"string","description":"The attribute can be compared on the frontend"},"is_used_for_promo_rules":{"type":"string","description":"The attribute can be used for promo rules"},"is_visible_on_front":{"type":"string","description":"The attribute is visible on the frontend"},"used_in_product_listing":{"type":"string","description":"The attribute can be used in product listing"},"is_visible":{"type":"boolean","description":"Attribute is visible on frontend."},"scope":{"type":"string","description":"Attribute scope"},"extension_attributes":{"$ref":"#/definitions/catalog-data-eav-attribute-extension-interface"},"attribute_id":{"type":"integer","description":"Id of the attribute."},"attribute_code":{"type":"string","description":"Code of the attribute."},"frontend_input":{"type":"string","description":"HTML for input element."},"entity_type_id":{"type":"string","description":"Entity type id"},"is_required":{"type":"boolean","description":"Attribute is required."},"options":{"type":"array","description":"Options of the attribute (key => value pairs for select)","items":{"$ref":"#/definitions/eav-data-attribute-option-interface"}},"is_user_defined":{"type":"boolean","description":"Current attribute has been defined by a user."},"default_frontend_label":{"type":"string","description":"Frontend label for default store"},"frontend_labels":{"type":"array","description":"Frontend label for each store","items":{"$ref":"#/definitions/eav-data-attribute-frontend-label-interface"}},"note":{"type":"string","description":"The note attribute for the element."},"backend_type":{"type":"string","description":"Backend type."},"backend_model":{"type":"string","description":"Backend model"},"source_model":{"type":"string","description":"Source model"},"default_value":{"type":"string","description":"Default value for the element."},"is_unique":{"type":"string","description":"This is a unique attribute"},"frontend_class":{"type":"string","description":"Frontend class of attribute"},"validation_rules":{"type":"array","description":"Validation rules.","items":{"$ref":"#/definitions/eav-data-attribute-validation-rule-interface"}},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["attribute_code","frontend_input","entity_type_id","is_required","frontend_labels"]},"catalog-data-eav-attribute-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\EavAttributeInterface"},"eav-data-attribute-option-interface":{"type":"object","description":"Created from:","properties":{"label":{"type":"string","description":"Option label"},"value":{"type":"string","description":"Option value"},"sort_order":{"type":"integer","description":"Option order"},"is_default":{"type":"boolean","description":"Default"},"store_labels":{"type":"array","description":"Option label for store scopes","items":{"$ref":"#/definitions/eav-data-attribute-option-label-interface"}}},"required":["label","value"]},"eav-data-attribute-option-label-interface":{"type":"object","description":"Interface AttributeOptionLabelInterface","properties":{"store_id":{"type":"integer","description":"Store id"},"label":{"type":"string","description":"Option label"}}},"eav-data-attribute-frontend-label-interface":{"type":"object","description":"Interface AttributeFrontendLabelInterface","properties":{"store_id":{"type":"integer","description":"Store id"},"label":{"type":"string","description":"Option label"}}},"eav-data-attribute-validation-rule-interface":{"type":"object","description":"Interface AttributeValidationRuleInterface","properties":{"key":{"type":"string","description":"Object key"},"value":{"type":"string","description":"Object value"}},"required":["key","value"]},"catalog-data-product-attribute-search-results-interface":{"type":"object","description":"","properties":{"items":{"type":"array","description":"Attributes list.","items":{"$ref":"#/definitions/catalog-data-product-attribute-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"catalog-data-category-attribute-interface":{"type":"object","description":"","properties":{"is_wysiwyg_enabled":{"type":"boolean","description":"WYSIWYG flag"},"is_html_allowed_on_front":{"type":"boolean","description":"The HTML tags are allowed on the frontend"},"used_for_sort_by":{"type":"boolean","description":"It is used for sorting in product listing"},"is_filterable":{"type":"boolean","description":"It used in layered navigation"},"is_filterable_in_search":{"type":"boolean","description":"It is used in search results layered navigation"},"is_used_in_grid":{"type":"boolean","description":"It is used in catalog product grid"},"is_visible_in_grid":{"type":"boolean","description":"It is visible in catalog product grid"},"is_filterable_in_grid":{"type":"boolean","description":"It is filterable in catalog product grid"},"position":{"type":"integer","description":"Position"},"apply_to":{"type":"array","description":"Apply to value for the element","items":{"type":"string"}},"is_searchable":{"type":"string","description":"The attribute can be used in Quick Search"},"is_visible_in_advanced_search":{"type":"string","description":"The attribute can be used in Advanced Search"},"is_comparable":{"type":"string","description":"The attribute can be compared on the frontend"},"is_used_for_promo_rules":{"type":"string","description":"The attribute can be used for promo rules"},"is_visible_on_front":{"type":"string","description":"The attribute is visible on the frontend"},"used_in_product_listing":{"type":"string","description":"The attribute can be used in product listing"},"is_visible":{"type":"boolean","description":"Attribute is visible on frontend."},"scope":{"type":"string","description":"Attribute scope"},"extension_attributes":{"$ref":"#/definitions/catalog-data-eav-attribute-extension-interface"},"attribute_id":{"type":"integer","description":"Id of the attribute."},"attribute_code":{"type":"string","description":"Code of the attribute."},"frontend_input":{"type":"string","description":"HTML for input element."},"entity_type_id":{"type":"string","description":"Entity type id"},"is_required":{"type":"boolean","description":"Attribute is required."},"options":{"type":"array","description":"Options of the attribute (key => value pairs for select)","items":{"$ref":"#/definitions/eav-data-attribute-option-interface"}},"is_user_defined":{"type":"boolean","description":"Current attribute has been defined by a user."},"default_frontend_label":{"type":"string","description":"Frontend label for default store"},"frontend_labels":{"type":"array","description":"Frontend label for each store","items":{"$ref":"#/definitions/eav-data-attribute-frontend-label-interface"}},"note":{"type":"string","description":"The note attribute for the element."},"backend_type":{"type":"string","description":"Backend type."},"backend_model":{"type":"string","description":"Backend model"},"source_model":{"type":"string","description":"Source model"},"default_value":{"type":"string","description":"Default value for the element."},"is_unique":{"type":"string","description":"This is a unique attribute"},"frontend_class":{"type":"string","description":"Frontend class of attribute"},"validation_rules":{"type":"array","description":"Validation rules.","items":{"$ref":"#/definitions/eav-data-attribute-validation-rule-interface"}},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["attribute_code","frontend_input","entity_type_id","is_required","frontend_labels"]},"catalog-data-category-attribute-search-results-interface":{"type":"object","description":"","properties":{"items":{"type":"array","description":"Attributes list.","items":{"$ref":"#/definitions/catalog-data-category-attribute-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"catalog-data-product-type-interface":{"type":"object","description":"Product type details","properties":{"name":{"type":"string","description":"Product type code"},"label":{"type":"string","description":"Product type label"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-type-extension-interface"}},"required":["name","label"]},"catalog-data-product-type-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductTypeInterface"},"eav-data-attribute-group-search-results-interface":{"type":"object","description":"Interface AttributeGroupSearchResultsInterface","properties":{"items":{"type":"array","description":"Attribute sets list.","items":{"$ref":"#/definitions/eav-data-attribute-group-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"eav-data-attribute-group-interface":{"type":"object","description":"Interface AttributeGroupInterface","properties":{"attribute_group_id":{"type":"string","description":"Id"},"attribute_group_name":{"type":"string","description":"Name"},"attribute_set_id":{"type":"integer","description":"Attribute set id"},"extension_attributes":{"$ref":"#/definitions/eav-data-attribute-group-extension-interface"}}},"eav-data-attribute-group-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Eav\\Api\\Data\\AttributeGroupInterface","properties":{"attribute_group_code":{"type":"string"},"sort_order":{"type":"string"}}},"catalog-data-tier-price-interface":{"type":"object","description":"Tier price interface.","properties":{"price":{"type":"number","description":"Tier price."},"price_type":{"type":"string","description":"Tier price type."},"website_id":{"type":"integer","description":"Website id."},"sku":{"type":"string","description":"SKU."},"customer_group":{"type":"string","description":"Customer group."},"quantity":{"type":"number","description":"Quantity."},"extension_attributes":{"$ref":"#/definitions/catalog-data-tier-price-extension-interface"}},"required":["price","price_type","website_id","sku","customer_group","quantity"]},"catalog-data-tier-price-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\TierPriceInterface"},"catalog-data-price-update-result-interface":{"type":"object","description":"Interface returned in case of incorrect price passed to efficient price API.","properties":{"message":{"type":"string","description":"Error message, that contains description of error occurred during price update."},"parameters":{"type":"array","description":"Parameters, that could be displayed in error message placeholders.","items":{"type":"string"}},"extension_attributes":{"$ref":"#/definitions/catalog-data-price-update-result-extension-interface"}},"required":["message","parameters"]},"catalog-data-price-update-result-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\PriceUpdateResultInterface"},"catalog-data-base-price-interface":{"type":"object","description":"Price interface.","properties":{"price":{"type":"number","description":"Price."},"store_id":{"type":"integer","description":"Store id."},"sku":{"type":"string","description":"SKU."},"extension_attributes":{"$ref":"#/definitions/catalog-data-base-price-extension-interface"}},"required":["price","store_id","sku"]},"catalog-data-base-price-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\BasePriceInterface"},"catalog-data-cost-interface":{"type":"object","description":"Cost interface.","properties":{"cost":{"type":"number","description":"Cost value."},"store_id":{"type":"integer","description":"Store id."},"sku":{"type":"string","description":"SKU."},"extension_attributes":{"$ref":"#/definitions/catalog-data-cost-extension-interface"}},"required":["cost","store_id","sku"]},"catalog-data-cost-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\CostInterface"},"catalog-data-special-price-interface":{"type":"object","description":"Product Special Price Interface is used to encapsulate data that can be processed by efficient price API.","properties":{"price":{"type":"number","description":"Product special price value."},"store_id":{"type":"integer","description":"ID of store, that contains special price value."},"sku":{"type":"string","description":"SKU of product, that contains special price value."},"price_from":{"type":"string","description":"Start date for special price in Y-m-d H:i:s format."},"price_to":{"type":"string","description":"End date for special price in Y-m-d H:i:s format."},"extension_attributes":{"$ref":"#/definitions/catalog-data-special-price-extension-interface"}},"required":["price","store_id","sku","price_from","price_to"]},"catalog-data-special-price-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\SpecialPriceInterface"},"catalog-data-category-interface":{"type":"object","description":"","properties":{"id":{"type":"integer"},"parent_id":{"type":"integer","description":"Parent category ID"},"name":{"type":"string","description":"Category name"},"is_active":{"type":"boolean","description":"Whether category is active"},"position":{"type":"integer","description":"Category position"},"level":{"type":"integer","description":"Category level"},"children":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"path":{"type":"string"},"available_sort_by":{"type":"array","items":{"type":"string"}},"include_in_menu":{"type":"boolean"},"extension_attributes":{"$ref":"#/definitions/catalog-data-category-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["name"]},"catalog-data-category-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\CategoryInterface"},"catalog-data-category-tree-interface":{"type":"object","description":"","properties":{"id":{"type":"integer"},"parent_id":{"type":"integer","description":"Parent category ID"},"name":{"type":"string","description":"Category name"},"is_active":{"type":"boolean","description":"Whether category is active"},"position":{"type":"integer","description":"Category position"},"level":{"type":"integer","description":"Category level"},"product_count":{"type":"integer","description":"Product count"},"children_data":{"type":"array","items":{"$ref":"#/definitions/catalog-data-category-tree-interface"}}},"required":["parent_id","name","is_active","position","level","product_count","children_data"]},"catalog-data-category-search-results-interface":{"type":"object","description":"","properties":{"items":{"type":"array","description":"Categories","items":{"$ref":"#/definitions/catalog-data-category-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"catalog-data-product-custom-option-type-interface":{"type":"object","description":"","properties":{"label":{"type":"string","description":"Option type label"},"code":{"type":"string","description":"Option type code"},"group":{"type":"string","description":"Option type group"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-custom-option-type-extension-interface"}},"required":["label","code","group"]},"catalog-data-product-custom-option-type-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductCustomOptionTypeInterface"},"catalog-data-product-link-type-interface":{"type":"object","description":"","properties":{"code":{"type":"integer","description":"Link type code"},"name":{"type":"string","description":"Link type name"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-link-type-extension-interface"}},"required":["code","name"]},"catalog-data-product-link-type-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductLinkTypeInterface"},"catalog-data-product-link-attribute-interface":{"type":"object","description":"","properties":{"code":{"type":"string","description":"Attribute code"},"type":{"type":"string","description":"Attribute type"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-link-attribute-extension-interface"}},"required":["code","type"]},"catalog-data-product-link-attribute-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductLinkAttributeInterface"},"catalog-data-category-product-link-interface":{"type":"object","description":"","properties":{"sku":{"type":"string"},"position":{"type":"integer"},"category_id":{"type":"string","description":"Category id"},"extension_attributes":{"$ref":"#/definitions/catalog-data-category-product-link-extension-interface"}},"required":["category_id"]},"catalog-data-category-product-link-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\CategoryProductLinkInterface"},"catalog-data-product-website-link-interface":{"type":"object","description":"","properties":{"sku":{"type":"string"},"website_id":{"type":"integer","description":"Website ids"}},"required":["sku","website_id"]},"catalog-data-product-render-search-results-interface":{"type":"object","description":"Dto that holds render information about products","properties":{"items":{"type":"array","description":"List of products rendered information","items":{"$ref":"#/definitions/catalog-data-product-render-interface"}}},"required":["items"]},"catalog-data-product-render-interface":{"type":"object","description":"Represents Data Object which holds enough information to render product This information is put into part as Add To Cart or Add to Compare Data or Price Data","properties":{"add_to_cart_button":{"$ref":"#/definitions/catalog-data-product-render-button-interface"},"add_to_compare_button":{"$ref":"#/definitions/catalog-data-product-render-button-interface"},"price_info":{"$ref":"#/definitions/catalog-data-product-render-price-info-interface"},"images":{"type":"array","description":"Enough information, that needed to render image on front","items":{"$ref":"#/definitions/catalog-data-product-render-image-interface"}},"url":{"type":"string","description":"Product url"},"id":{"type":"integer","description":"Product identifier"},"name":{"type":"string","description":"Product name"},"type":{"type":"string","description":"Product type. Such as bundle, grouped, simple, etc..."},"is_salable":{"type":"string","description":"Information about product saleability (In Stock)"},"store_id":{"type":"integer","description":"Information about current store id or requested store id"},"currency_code":{"type":"string","description":"Current or desired currency code to product"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-render-extension-interface"}},"required":["add_to_cart_button","add_to_compare_button","price_info","images","url","id","name","type","is_salable","store_id","currency_code","extension_attributes"]},"catalog-data-product-render-button-interface":{"type":"object","description":"Button interface. This interface represents all manner of product buttons: add to cart, add to compare, etc... The buttons describes by this interface should have interaction with backend","properties":{"post_data":{"type":"string","description":"Post data"},"url":{"type":"string","description":"Url, needed to add product to cart"},"required_options":{"type":"boolean","description":"Flag whether a product has options or not"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-render-button-extension-interface"}},"required":["post_data","url","required_options"]},"catalog-data-product-render-button-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductRender\\ButtonInterface"},"catalog-data-product-render-price-info-interface":{"type":"object","description":"Price interface.","properties":{"final_price":{"type":"number","description":"Final price"},"max_price":{"type":"number","description":"Max price of a product"},"max_regular_price":{"type":"number","description":"Max regular price"},"minimal_regular_price":{"type":"number","description":"Minimal regular price"},"special_price":{"type":"number","description":"Special price"},"minimal_price":{"type":"number"},"regular_price":{"type":"number","description":"Regular price"},"formatted_prices":{"$ref":"#/definitions/catalog-data-product-render-formatted-price-info-interface"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-render-price-info-extension-interface"}},"required":["final_price","max_price","max_regular_price","minimal_regular_price","special_price","minimal_price","regular_price","formatted_prices"]},"catalog-data-product-render-formatted-price-info-interface":{"type":"object","description":"Formatted Price interface. Aggregate formatted html with price representations. E.g.: $9.00 Consider currency, rounding and html","properties":{"final_price":{"type":"string","description":"Html with final price"},"max_price":{"type":"string","description":"Max price of a product"},"minimal_price":{"type":"string","description":"The minimal price of the product or variation"},"max_regular_price":{"type":"string","description":"Max regular price"},"minimal_regular_price":{"type":"string","description":"Minimal regular price"},"special_price":{"type":"string","description":"Special price"},"regular_price":{"type":"string","description":"Price - is price of product without discounts and special price with taxes and fixed product tax"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-render-formatted-price-info-extension-interface"}},"required":["final_price","max_price","minimal_price","max_regular_price","minimal_regular_price","special_price","regular_price"]},"catalog-data-product-render-formatted-price-info-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductRender\\FormattedPriceInfoInterface"},"catalog-data-product-render-price-info-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductRender\\PriceInfoInterface","properties":{"msrp":{"$ref":"#/definitions/msrp-data-product-render-msrp-price-info-interface"},"tax_adjustments":{"$ref":"#/definitions/catalog-data-product-render-price-info-interface"},"weee_attributes":{"type":"array","items":{"$ref":"#/definitions/weee-data-product-render-weee-adjustment-attribute-interface"}},"weee_adjustment":{"type":"string"}}},"msrp-data-product-render-msrp-price-info-interface":{"type":"object","description":"Price interface.","properties":{"msrp_price":{"type":"string"},"is_applicable":{"type":"string"},"is_shown_price_on_gesture":{"type":"string"},"msrp_message":{"type":"string"},"explanation_message":{"type":"string"},"extension_attributes":{"$ref":"#/definitions/msrp-data-product-render-msrp-price-info-extension-interface"}},"required":["msrp_price","is_applicable","is_shown_price_on_gesture","msrp_message","explanation_message"]},"msrp-data-product-render-msrp-price-info-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Msrp\\Api\\Data\\ProductRender\\MsrpPriceInfoInterface"},"weee-data-product-render-weee-adjustment-attribute-interface":{"type":"object","description":"List of all weee attributes, their amounts, etc.., that product has","properties":{"amount":{"type":"string","description":"Weee attribute amount"},"tax_amount":{"type":"string","description":"Tax which is calculated to fixed product tax attribute"},"tax_amount_incl_tax":{"type":"string","description":"Tax amount of weee attribute"},"amount_excl_tax":{"type":"string","description":"Product amount exclude tax"},"attribute_code":{"type":"string","description":"Weee attribute code"},"extension_attributes":{"$ref":"#/definitions/weee-data-product-render-weee-adjustment-attribute-extension-interface"}},"required":["amount","tax_amount","tax_amount_incl_tax","amount_excl_tax","attribute_code","extension_attributes"]},"weee-data-product-render-weee-adjustment-attribute-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Weee\\Api\\Data\\ProductRender\\WeeeAdjustmentAttributeInterface"},"catalog-data-product-render-image-interface":{"type":"object","description":"Product Render image interface. Represents physical characteristics of image, that can be used in product listing or product view","properties":{"url":{"type":"string","description":"Image url"},"code":{"type":"string","description":"Image code"},"height":{"type":"number","description":"Image height"},"width":{"type":"number","description":"Image width in px"},"label":{"type":"string","description":"Image label"},"resized_width":{"type":"number","description":"Resize width"},"resized_height":{"type":"number","description":"Resize height"},"extension_attributes":{"$ref":"#/definitions/catalog-data-product-render-image-extension-interface"}},"required":["url","code","height","width","label","resized_width","resized_height"]},"catalog-data-product-render-image-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductRender\\ImageInterface"},"catalog-data-product-render-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductRenderInterface","properties":{"wishlist_button":{"$ref":"#/definitions/catalog-data-product-render-button-interface"},"review_html":{"type":"string"}}},"catalog-inventory-data-stock-status-collection-interface":{"type":"object","description":"Stock Status collection interface","properties":{"items":{"type":"array","description":"Items","items":{"$ref":"#/definitions/catalog-inventory-data-stock-status-interface"}},"search_criteria":{"$ref":"#/definitions/catalog-inventory-stock-status-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"catalog-inventory-data-stock-status-interface":{"type":"object","description":"Interface StockStatusInterface","properties":{"product_id":{"type":"integer"},"stock_id":{"type":"integer"},"qty":{"type":"integer"},"stock_status":{"type":"integer"},"stock_item":{"$ref":"#/definitions/catalog-inventory-data-stock-item-interface"},"extension_attributes":{"$ref":"#/definitions/catalog-inventory-data-stock-status-extension-interface"}},"required":["product_id","stock_id","qty","stock_status","stock_item"]},"catalog-inventory-data-stock-status-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\CatalogInventory\\Api\\Data\\StockStatusInterface"},"catalog-inventory-stock-status-criteria-interface":{"type":"object","description":"Interface StockStatusCriteriaInterface","properties":{"mapper_interface_name":{"type":"string","description":"Associated Mapper Interface name"},"criteria_list":{"type":"array","description":"Criteria objects added to current Composite Criteria","items":{"$ref":"#/definitions/framework-criteria-interface"}},"filters":{"type":"array","description":"List of filters","items":{"type":"string"}},"orders":{"type":"array","description":"Ordering criteria","items":{"type":"string"}},"limit":{"type":"array","description":"Limit","items":{"type":"string"}}},"required":["mapper_interface_name","criteria_list","filters","orders","limit"]},"framework-criteria-interface":{"type":"object","description":"Interface CriteriaInterface","properties":{"mapper_interface_name":{"type":"string","description":"Associated Mapper Interface name"},"criteria_list":{"type":"array","description":"Criteria objects added to current Composite Criteria","items":{"$ref":"#/definitions/framework-criteria-interface"}},"filters":{"type":"array","description":"List of filters","items":{"type":"string"}},"orders":{"type":"array","description":"Ordering criteria","items":{"type":"string"}},"limit":{"type":"array","description":"Limit","items":{"type":"string"}}},"required":["mapper_interface_name","criteria_list","filters","orders","limit"]},"bundle-data-option-type-interface":{"type":"object","description":"Interface OptionTypeInterface","properties":{"label":{"type":"string","description":"Type label"},"code":{"type":"string","description":"Type code"},"extension_attributes":{"$ref":"#/definitions/bundle-data-option-type-extension-interface"}},"required":["label","code"]},"bundle-data-option-type-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Bundle\\Api\\Data\\OptionTypeInterface"},"quote-data-cart-interface":{"type":"object","description":"Interface CartInterface","properties":{"id":{"type":"integer","description":"Cart/quote ID."},"created_at":{"type":"string","description":"Cart creation date and time. Otherwise, null."},"updated_at":{"type":"string","description":"Cart last update date and time. Otherwise, null."},"converted_at":{"type":"string","description":"Cart conversion date and time. Otherwise, null."},"is_active":{"type":"boolean","description":"Active status flag value. Otherwise, null."},"is_virtual":{"type":"boolean","description":"Virtual flag value. Otherwise, null."},"items":{"type":"array","description":"Array of items. Otherwise, null.","items":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"items_count":{"type":"integer","description":"Number of different items or products in the cart. Otherwise, null."},"items_qty":{"type":"number","description":"Total quantity of all cart items. Otherwise, null."},"customer":{"$ref":"#/definitions/customer-data-customer-interface"},"billing_address":{"$ref":"#/definitions/quote-data-address-interface"},"reserved_order_id":{"type":"integer","description":"Reserved order ID. Otherwise, null."},"orig_order_id":{"type":"integer","description":"Original order ID. Otherwise, null."},"currency":{"$ref":"#/definitions/quote-data-currency-interface"},"customer_is_guest":{"type":"boolean","description":"For guest customers, false for logged in customers"},"customer_note":{"type":"string","description":"Notice text"},"customer_note_notify":{"type":"boolean","description":"Customer notification flag"},"customer_tax_class_id":{"type":"integer","description":"Customer tax class ID."},"store_id":{"type":"integer","description":"Store identifier"},"extension_attributes":{"$ref":"#/definitions/quote-data-cart-extension-interface"}},"required":["id","customer","store_id"]},"quote-data-cart-item-interface":{"type":"object","description":"Interface CartItemInterface","properties":{"item_id":{"type":"integer","description":"Item ID. Otherwise, null."},"sku":{"type":"string","description":"Product SKU. Otherwise, null."},"qty":{"type":"number","description":"Product quantity."},"name":{"type":"string","description":"Product name. Otherwise, null."},"price":{"type":"number","description":"Product price. Otherwise, null."},"product_type":{"type":"string","description":"Product type. Otherwise, null."},"quote_id":{"type":"string","description":"Quote id."},"product_option":{"$ref":"#/definitions/quote-data-product-option-interface"},"extension_attributes":{"$ref":"#/definitions/quote-data-cart-item-extension-interface"}},"required":["qty","quote_id"]},"quote-data-product-option-interface":{"type":"object","description":"Product option interface","properties":{"extension_attributes":{"$ref":"#/definitions/quote-data-product-option-extension-interface"}}},"quote-data-product-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\ProductOptionInterface","properties":{"custom_options":{"type":"array","items":{"$ref":"#/definitions/catalog-data-custom-option-interface"}},"bundle_options":{"type":"array","items":{"$ref":"#/definitions/bundle-data-bundle-option-interface"}},"downloadable_option":{"$ref":"#/definitions/downloadable-data-downloadable-option-interface"},"giftcard_item_option":{"$ref":"#/definitions/gift-card-data-gift-card-option-interface"},"configurable_item_options":{"type":"array","items":{"$ref":"#/definitions/configurable-product-data-configurable-item-option-value-interface"}}}},"catalog-data-custom-option-interface":{"type":"object","description":"Interface CustomOptionInterface","properties":{"option_id":{"type":"string","description":"Option id"},"option_value":{"type":"string","description":"Option value"},"extension_attributes":{"$ref":"#/definitions/catalog-data-custom-option-extension-interface"}},"required":["option_id","option_value"]},"catalog-data-custom-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\CustomOptionInterface","properties":{"file_info":{"$ref":"#/definitions/framework-data-image-content-interface"}}},"bundle-data-bundle-option-interface":{"type":"object","description":"Interface BundleOptionInterface","properties":{"option_id":{"type":"integer","description":"Bundle option id."},"option_qty":{"type":"integer","description":"Bundle option quantity."},"option_selections":{"type":"array","description":"Bundle option selection ids.","items":{"type":"integer"}},"extension_attributes":{"$ref":"#/definitions/bundle-data-bundle-option-extension-interface"}},"required":["option_id","option_qty","option_selections"]},"bundle-data-bundle-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Bundle\\Api\\Data\\BundleOptionInterface"},"downloadable-data-downloadable-option-interface":{"type":"object","description":"Downloadable Option","properties":{"downloadable_links":{"type":"array","description":"The list of downloadable links","items":{"type":"integer"}}},"required":["downloadable_links"]},"gift-card-data-gift-card-option-interface":{"type":"object","description":"Interface GiftCardOptionInterface","properties":{"giftcard_amount":{"type":"string","description":"Gift card amount."},"custom_giftcard_amount":{"type":"number","description":"Gift card open amount value."},"giftcard_sender_name":{"type":"string","description":"Gift card sender name."},"giftcard_recipient_name":{"type":"string","description":"Gift card recipient name."},"giftcard_sender_email":{"type":"string","description":"Gift card sender email."},"giftcard_recipient_email":{"type":"string","description":"Gift card recipient email."},"giftcard_message":{"type":"string","description":"Giftcard message."},"extension_attributes":{"$ref":"#/definitions/gift-card-data-gift-card-option-extension-interface"}},"required":["giftcard_amount","giftcard_sender_name","giftcard_recipient_name","giftcard_sender_email","giftcard_recipient_email"]},"gift-card-data-gift-card-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\GiftCard\\Api\\Data\\GiftCardOptionInterface"},"configurable-product-data-configurable-item-option-value-interface":{"type":"object","description":"Interface ConfigurableItemOptionValueInterface","properties":{"option_id":{"type":"string","description":"Option SKU"},"option_value":{"type":"integer","description":"Item id"},"extension_attributes":{"$ref":"#/definitions/configurable-product-data-configurable-item-option-value-extension-interface"}},"required":["option_id"]},"configurable-product-data-configurable-item-option-value-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\ConfigurableProduct\\Api\\Data\\ConfigurableItemOptionValueInterface"},"quote-data-cart-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\CartItemInterface"},"quote-data-address-interface":{"type":"object","description":"Interface AddressInterface","properties":{"id":{"type":"integer","description":"Id"},"region":{"type":"string","description":"Region name"},"region_id":{"type":"integer","description":"Region id"},"region_code":{"type":"string","description":"Region code"},"country_id":{"type":"string","description":"Country id"},"street":{"type":"array","description":"Street","items":{"type":"string"}},"company":{"type":"string","description":"Company"},"telephone":{"type":"string","description":"Telephone number"},"fax":{"type":"string","description":"Fax number"},"postcode":{"type":"string","description":"Postcode"},"city":{"type":"string","description":"City name"},"firstname":{"type":"string","description":"First name"},"lastname":{"type":"string","description":"Last name"},"middlename":{"type":"string","description":"Middle name"},"prefix":{"type":"string","description":"Prefix"},"suffix":{"type":"string","description":"Suffix"},"vat_id":{"type":"string","description":"Vat id"},"customer_id":{"type":"integer","description":"Customer id"},"email":{"type":"string","description":"Billing/shipping email"},"same_as_billing":{"type":"integer","description":"Same as billing flag"},"customer_address_id":{"type":"integer","description":"Customer address id"},"save_in_address_book":{"type":"integer","description":"Save in address book flag"},"extension_attributes":{"$ref":"#/definitions/quote-data-address-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["region","region_id","region_code","country_id","street","telephone","postcode","city","firstname","lastname","email"]},"quote-data-address-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\AddressInterface","properties":{"gift_registry_id":{"type":"integer"}}},"quote-data-currency-interface":{"type":"object","description":"Interface CurrencyInterface","properties":{"global_currency_code":{"type":"string","description":"Global currency code"},"base_currency_code":{"type":"string","description":"Base currency code"},"store_currency_code":{"type":"string","description":"Store currency code"},"quote_currency_code":{"type":"string","description":"Quote currency code"},"store_to_base_rate":{"type":"number","description":"Store currency to base currency rate"},"store_to_quote_rate":{"type":"number","description":"Store currency to quote currency rate"},"base_to_global_rate":{"type":"number","description":"Base currency to global currency rate"},"base_to_quote_rate":{"type":"number","description":"Base currency to quote currency rate"},"extension_attributes":{"$ref":"#/definitions/quote-data-currency-extension-interface"}}},"quote-data-currency-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\CurrencyInterface"},"quote-data-cart-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\CartInterface","properties":{"shipping_assignments":{"type":"array","items":{"$ref":"#/definitions/quote-data-shipping-assignment-interface"}},"quote_api_test_attribute":{"$ref":"#/definitions/user-data-user-interface"}}},"quote-data-shipping-assignment-interface":{"type":"object","description":"Interface ShippingAssignmentInterface","properties":{"shipping":{"$ref":"#/definitions/quote-data-shipping-interface"},"items":{"type":"array","items":{"$ref":"#/definitions/quote-data-cart-item-interface"}},"extension_attributes":{"$ref":"#/definitions/quote-data-shipping-assignment-extension-interface"}},"required":["shipping","items"]},"quote-data-shipping-interface":{"type":"object","description":"Interface ShippingInterface","properties":{"address":{"$ref":"#/definitions/quote-data-address-interface"},"method":{"type":"string","description":"Shipping method"},"extension_attributes":{"$ref":"#/definitions/quote-data-shipping-extension-interface"}},"required":["address","method"]},"quote-data-shipping-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\ShippingInterface"},"quote-data-shipping-assignment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\ShippingAssignmentInterface"},"user-data-user-interface":{"type":"object","description":"Admin user interface.","properties":{"id":{"type":"integer","description":"ID."},"first_name":{"type":"string","description":"First name."},"last_name":{"type":"string","description":"Last name."},"email":{"type":"string","description":"Email."},"user_name":{"type":"string","description":"User name."},"password":{"type":"string","description":"Password or password hash."},"created":{"type":"string","description":"User record creation date."},"modified":{"type":"string","description":"User record modification date."},"is_active":{"type":"integer","description":"If user is active."},"interface_locale":{"type":"string","description":"User interface locale."}},"required":["id","first_name","last_name","email","user_name","password","created","modified","is_active","interface_locale"]},"quote-data-cart-search-results-interface":{"type":"object","description":"Interface CartSearchResultsInterface","properties":{"items":{"type":"array","description":"Carts list.","items":{"$ref":"#/definitions/quote-data-cart-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"quote-data-payment-interface":{"type":"object","description":"Interface PaymentInterface","properties":{"po_number":{"type":"string","description":"Purchase order number"},"method":{"type":"string","description":"Payment method code"},"additional_data":{"type":"array","description":"Payment additional details","items":{"type":"string"}},"extension_attributes":{"$ref":"#/definitions/quote-data-payment-extension-interface"}},"required":["method"]},"quote-data-payment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\PaymentInterface","properties":{"agreement_ids":{"type":"array","items":{"type":"string"}}}},"quote-data-shipping-method-interface":{"type":"object","description":"Interface ShippingMethodInterface","properties":{"carrier_code":{"type":"string","description":"Shipping carrier code."},"method_code":{"type":"string","description":"Shipping method code."},"carrier_title":{"type":"string","description":"Shipping carrier title. Otherwise, null."},"method_title":{"type":"string","description":"Shipping method title. Otherwise, null."},"amount":{"type":"number","description":"Shipping amount in store currency."},"base_amount":{"type":"number","description":"Shipping amount in base currency."},"available":{"type":"boolean","description":"The value of the availability flag for the current shipping method."},"extension_attributes":{"$ref":"#/definitions/quote-data-shipping-method-extension-interface"},"error_message":{"type":"string","description":"Shipping Error message."},"price_excl_tax":{"type":"number","description":"Shipping price excl tax."},"price_incl_tax":{"type":"number","description":"Shipping price incl tax."}},"required":["carrier_code","method_code","amount","base_amount","available","error_message","price_excl_tax","price_incl_tax"]},"quote-data-shipping-method-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\ShippingMethodInterface"},"quote-data-payment-method-interface":{"type":"object","description":"Interface PaymentMethodInterface","properties":{"code":{"type":"string","description":"Payment method code"},"title":{"type":"string","description":"Payment method title"}},"required":["code","title"]},"quote-data-totals-interface":{"type":"object","description":"Interface TotalsInterface","properties":{"grand_total":{"type":"number","description":"Grand total in quote currency"},"base_grand_total":{"type":"number","description":"Grand total in base currency"},"subtotal":{"type":"number","description":"Subtotal in quote currency"},"base_subtotal":{"type":"number","description":"Subtotal in base currency"},"discount_amount":{"type":"number","description":"Discount amount in quote currency"},"base_discount_amount":{"type":"number","description":"Discount amount in base currency"},"subtotal_with_discount":{"type":"number","description":"Subtotal in quote currency with applied discount"},"base_subtotal_with_discount":{"type":"number","description":"Subtotal in base currency with applied discount"},"shipping_amount":{"type":"number","description":"Shipping amount in quote currency"},"base_shipping_amount":{"type":"number","description":"Shipping amount in base currency"},"shipping_discount_amount":{"type":"number","description":"Shipping discount amount in quote currency"},"base_shipping_discount_amount":{"type":"number","description":"Shipping discount amount in base currency"},"tax_amount":{"type":"number","description":"Tax amount in quote currency"},"base_tax_amount":{"type":"number","description":"Tax amount in base currency"},"weee_tax_applied_amount":{"type":"number","description":"Item weee tax applied amount in quote currency."},"shipping_tax_amount":{"type":"number","description":"Shipping tax amount in quote currency"},"base_shipping_tax_amount":{"type":"number","description":"Shipping tax amount in base currency"},"subtotal_incl_tax":{"type":"number","description":"Subtotal including tax in quote currency"},"base_subtotal_incl_tax":{"type":"number","description":"Subtotal including tax in base currency"},"shipping_incl_tax":{"type":"number","description":"Shipping including tax in quote currency"},"base_shipping_incl_tax":{"type":"number","description":"Shipping including tax in base currency"},"base_currency_code":{"type":"string","description":"Base currency code"},"quote_currency_code":{"type":"string","description":"Quote currency code"},"coupon_code":{"type":"string","description":"Applied coupon code"},"items_qty":{"type":"integer","description":"Items qty"},"items":{"type":"array","description":"Totals by items","items":{"$ref":"#/definitions/quote-data-totals-item-interface"}},"total_segments":{"type":"array","description":"Dynamically calculated totals","items":{"$ref":"#/definitions/quote-data-total-segment-interface"}},"extension_attributes":{"$ref":"#/definitions/quote-data-totals-extension-interface"}},"required":["weee_tax_applied_amount","total_segments"]},"quote-data-totals-item-interface":{"type":"object","description":"Interface TotalsItemInterface","properties":{"item_id":{"type":"integer","description":"Item id"},"price":{"type":"number","description":"Item price in quote currency."},"base_price":{"type":"number","description":"Item price in base currency."},"qty":{"type":"number","description":"Item quantity."},"row_total":{"type":"number","description":"Row total in quote currency."},"base_row_total":{"type":"number","description":"Row total in base currency."},"row_total_with_discount":{"type":"number","description":"Row total with discount in quote currency. Otherwise, null."},"tax_amount":{"type":"number","description":"Tax amount in quote currency. Otherwise, null."},"base_tax_amount":{"type":"number","description":"Tax amount in base currency. Otherwise, null."},"tax_percent":{"type":"number","description":"Tax percent. Otherwise, null."},"discount_amount":{"type":"number","description":"Discount amount in quote currency. Otherwise, null."},"base_discount_amount":{"type":"number","description":"Discount amount in base currency. Otherwise, null."},"discount_percent":{"type":"number","description":"Discount percent. Otherwise, null."},"price_incl_tax":{"type":"number","description":"Price including tax in quote currency. Otherwise, null."},"base_price_incl_tax":{"type":"number","description":"Price including tax in base currency. Otherwise, null."},"row_total_incl_tax":{"type":"number","description":"Row total including tax in quote currency. Otherwise, null."},"base_row_total_incl_tax":{"type":"number","description":"Row total including tax in base currency. Otherwise, null."},"options":{"type":"string","description":"Item price in quote currency."},"weee_tax_applied_amount":{"type":"number","description":"Item weee tax applied amount in quote currency."},"weee_tax_applied":{"type":"string","description":"Item weee tax applied in quote currency."},"extension_attributes":{"$ref":"#/definitions/quote-data-totals-item-extension-interface"},"name":{"type":"string","description":"Product name. Otherwise, null."}},"required":["item_id","price","base_price","qty","row_total","base_row_total","options","weee_tax_applied_amount","weee_tax_applied"]},"quote-data-totals-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\TotalsItemInterface"},"quote-data-total-segment-interface":{"type":"object","description":"Interface TotalsInterface","properties":{"code":{"type":"string","description":"Code"},"title":{"type":"string","description":"Total title"},"value":{"type":"number","description":"Total value"},"area":{"type":"string","description":"Display area code."},"extension_attributes":{"$ref":"#/definitions/quote-data-total-segment-extension-interface"}},"required":["code","value"]},"quote-data-total-segment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\TotalSegmentInterface","properties":{"gift_cards":{"type":"string"},"tax_grandtotal_details":{"type":"array","items":{"$ref":"#/definitions/tax-data-grand-total-details-interface"}},"gw_order_id":{"type":"string"},"gw_item_ids":{"type":"array","items":{"type":"string"}},"gw_allow_gift_receipt":{"type":"string"},"gw_add_card":{"type":"string"},"gw_price":{"type":"string"},"gw_base_price":{"type":"string"},"gw_items_price":{"type":"string"},"gw_items_base_price":{"type":"string"},"gw_card_price":{"type":"string"},"gw_card_base_price":{"type":"string"},"gw_base_tax_amount":{"type":"string"},"gw_tax_amount":{"type":"string"},"gw_items_base_tax_amount":{"type":"string"},"gw_items_tax_amount":{"type":"string"},"gw_card_base_tax_amount":{"type":"string"},"gw_card_tax_amount":{"type":"string"},"gw_price_incl_tax":{"type":"string"},"gw_base_price_incl_tax":{"type":"string"},"gw_card_price_incl_tax":{"type":"string"},"gw_card_base_price_incl_tax":{"type":"string"},"gw_items_price_incl_tax":{"type":"string"},"gw_items_base_price_incl_tax":{"type":"string"}}},"tax-data-grand-total-details-interface":{"type":"object","description":"Interface GrandTotalDetailsInterface","properties":{"amount":{"type":"number","description":"Tax amount value"},"rates":{"type":"array","description":"Tax rates info","items":{"$ref":"#/definitions/tax-data-grand-total-rates-interface"}},"group_id":{"type":"integer","description":"Group identifier"}},"required":["amount","rates","group_id"]},"tax-data-grand-total-rates-interface":{"type":"object","description":"Interface GrandTotalRatesInterface","properties":{"percent":{"type":"string","description":"Tax percentage value"},"title":{"type":"string","description":"Rate title"}},"required":["percent","title"]},"quote-data-totals-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\TotalsInterface","properties":{"coupon_label":{"type":"string"},"base_customer_balance_amount":{"type":"number"},"customer_balance_amount":{"type":"number"},"reward_points_balance":{"type":"number"},"reward_currency_amount":{"type":"number"},"base_reward_currency_amount":{"type":"number"}}},"quote-data-totals-additional-data-interface":{"type":"object","description":"Additional data for totals collection.","properties":{"extension_attributes":{"$ref":"#/definitions/quote-data-totals-additional-data-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}}},"quote-data-totals-additional-data-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Quote\\Api\\Data\\TotalsAdditionalDataInterface","properties":{"gift_messages":{"type":"array","items":{"$ref":"#/definitions/gift-message-data-message-interface"}}}},"gift-message-data-message-interface":{"type":"object","description":"Interface MessageInterface","properties":{"gift_message_id":{"type":"integer","description":"Gift message ID. Otherwise, null."},"customer_id":{"type":"integer","description":"Customer ID. Otherwise, null."},"sender":{"type":"string","description":"Sender name."},"recipient":{"type":"string","description":"Recipient name."},"message":{"type":"string","description":"Message text."},"extension_attributes":{"$ref":"#/definitions/gift-message-data-message-extension-interface"}},"required":["sender","recipient","message"]},"gift-message-data-message-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\GiftMessage\\Api\\Data\\MessageInterface","properties":{"entity_id":{"type":"string"},"entity_type":{"type":"string"},"wrapping_id":{"type":"integer"},"wrapping_allow_gift_receipt":{"type":"boolean"},"wrapping_add_printed_card":{"type":"boolean"}}},"framework-search-search-result-interface":{"type":"object","description":"Interface SearchResultInterface","properties":{"items":{"type":"array","items":{"$ref":"#/definitions/framework-search-document-interface"}},"aggregations":{"$ref":"#/definitions/framework-search-aggregation-interface"},"search_criteria":{"$ref":"#/definitions/framework-search-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","aggregations","search_criteria","total_count"]},"framework-search-document-interface":{"type":"object","description":"Interface \\Magento\\Framework\\Api\\Search\\DocumentInterface","properties":{"id":{"type":"integer"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["id"]},"framework-search-aggregation-interface":{"type":"object","description":"Faceted data","properties":{"buckets":{"type":"array","description":"All Document fields","items":{"$ref":"#/definitions/framework-search-bucket-interface"}},"bucket_names":{"type":"array","description":"Document field names","items":{"type":"string"}}},"required":["buckets","bucket_names"]},"framework-search-bucket-interface":{"type":"object","description":"Facet Bucket","properties":{"name":{"type":"string","description":"Field name"},"values":{"type":"array","description":"Field values","items":{"$ref":"#/definitions/framework-search-aggregation-value-interface"}}},"required":["name","values"]},"framework-search-aggregation-value-interface":{"type":"object","description":"Interface \\Magento\\Framework\\Api\\Search\\AggregationValueInterface","properties":{"value":{"type":"string","description":"Aggregation"},"metrics":{"type":"array","description":"Metrics","items":{"type":"string"}}},"required":["value","metrics"]},"framework-search-search-criteria-interface":{"type":"object","description":"Interface SearchCriteriaInterface","properties":{"request_name":{"type":"string"},"filter_groups":{"type":"array","description":"A list of filter groups.","items":{"$ref":"#/definitions/framework-search-filter-group"}},"sort_orders":{"type":"array","description":"Sort order.","items":{"$ref":"#/definitions/framework-sort-order"}},"page_size":{"type":"integer","description":"Page size."},"current_page":{"type":"integer","description":"Current page."}},"required":["request_name","filter_groups"]},"sales-data-order-interface":{"type":"object","description":"Order interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"adjustment_negative":{"type":"number","description":"Negative adjustment value."},"adjustment_positive":{"type":"number","description":"Positive adjustment value."},"applied_rule_ids":{"type":"string","description":"Applied rule IDs."},"base_adjustment_negative":{"type":"number","description":"Base negative adjustment value."},"base_adjustment_positive":{"type":"number","description":"Base positive adjustment value."},"base_currency_code":{"type":"string","description":"Base currency code."},"base_discount_amount":{"type":"number","description":"Base discount amount."},"base_discount_canceled":{"type":"number","description":"Base discount canceled."},"base_discount_invoiced":{"type":"number","description":"Base discount invoiced."},"base_discount_refunded":{"type":"number","description":"Base discount refunded."},"base_grand_total":{"type":"number","description":"Base grand total."},"base_discount_tax_compensation_amount":{"type":"number","description":"Base discount tax compensation amount."},"base_discount_tax_compensation_invoiced":{"type":"number","description":"Base discount tax compensation invoiced."},"base_discount_tax_compensation_refunded":{"type":"number","description":"Base discount tax compensation refunded."},"base_shipping_amount":{"type":"number","description":"Base shipping amount."},"base_shipping_canceled":{"type":"number","description":"Base shipping canceled."},"base_shipping_discount_amount":{"type":"number","description":"Base shipping discount amount."},"base_shipping_discount_tax_compensation_amnt":{"type":"number","description":"Base shipping discount tax compensation amount."},"base_shipping_incl_tax":{"type":"number","description":"Base shipping including tax."},"base_shipping_invoiced":{"type":"number","description":"Base shipping invoiced."},"base_shipping_refunded":{"type":"number","description":"Base shipping refunded."},"base_shipping_tax_amount":{"type":"number","description":"Base shipping tax amount."},"base_shipping_tax_refunded":{"type":"number","description":"Base shipping tax refunded."},"base_subtotal":{"type":"number","description":"Base subtotal."},"base_subtotal_canceled":{"type":"number","description":"Base subtotal canceled."},"base_subtotal_incl_tax":{"type":"number","description":"Base subtotal including tax."},"base_subtotal_invoiced":{"type":"number","description":"Base subtotal invoiced."},"base_subtotal_refunded":{"type":"number","description":"Base subtotal refunded."},"base_tax_amount":{"type":"number","description":"Base tax amount."},"base_tax_canceled":{"type":"number","description":"Base tax canceled."},"base_tax_invoiced":{"type":"number","description":"Base tax invoiced."},"base_tax_refunded":{"type":"number","description":"Base tax refunded."},"base_total_canceled":{"type":"number","description":"Base total canceled."},"base_total_due":{"type":"number","description":"Base total due."},"base_total_invoiced":{"type":"number","description":"Base total invoiced."},"base_total_invoiced_cost":{"type":"number","description":"Base total invoiced cost."},"base_total_offline_refunded":{"type":"number","description":"Base total offline refunded."},"base_total_online_refunded":{"type":"number","description":"Base total online refunded."},"base_total_paid":{"type":"number","description":"Base total paid."},"base_total_qty_ordered":{"type":"number","description":"Base total quantity ordered."},"base_total_refunded":{"type":"number","description":"Base total refunded."},"base_to_global_rate":{"type":"number","description":"Base-to-global rate."},"base_to_order_rate":{"type":"number","description":"Base-to-order rate."},"billing_address_id":{"type":"integer","description":"Billing address ID."},"can_ship_partially":{"type":"integer","description":"Can-ship-partially flag value."},"can_ship_partially_item":{"type":"integer","description":"Can-ship-partially-item flag value."},"coupon_code":{"type":"string","description":"Coupon code."},"created_at":{"type":"string","description":"Created-at timestamp."},"customer_dob":{"type":"string","description":"Customer date-of-birth (DOB)."},"customer_email":{"type":"string","description":"Customer email address."},"customer_firstname":{"type":"string","description":"Customer first name."},"customer_gender":{"type":"integer","description":"Customer gender."},"customer_group_id":{"type":"integer","description":"Customer group ID."},"customer_id":{"type":"integer","description":"Customer ID."},"customer_is_guest":{"type":"integer","description":"Customer-is-guest flag value."},"customer_lastname":{"type":"string","description":"Customer last name."},"customer_middlename":{"type":"string","description":"Customer middle name."},"customer_note":{"type":"string","description":"Customer note."},"customer_note_notify":{"type":"integer","description":"Customer-note-notify flag value."},"customer_prefix":{"type":"string","description":"Customer prefix."},"customer_suffix":{"type":"string","description":"Customer suffix."},"customer_taxvat":{"type":"string","description":"Customer value-added tax (VAT)."},"discount_amount":{"type":"number","description":"Discount amount."},"discount_canceled":{"type":"number","description":"Discount canceled."},"discount_description":{"type":"string","description":"Discount description."},"discount_invoiced":{"type":"number","description":"Discount invoiced."},"discount_refunded":{"type":"number","description":"Discount refunded amount."},"edit_increment":{"type":"integer","description":"Edit increment value."},"email_sent":{"type":"integer","description":"Email-sent flag value."},"entity_id":{"type":"integer","description":"Order ID."},"ext_customer_id":{"type":"string","description":"External customer ID."},"ext_order_id":{"type":"string","description":"External order ID."},"forced_shipment_with_invoice":{"type":"integer","description":"Forced-shipment-with-invoice flag value."},"global_currency_code":{"type":"string","description":"Global currency code."},"grand_total":{"type":"number","description":"Grand total."},"discount_tax_compensation_amount":{"type":"number","description":"Discount tax compensation amount."},"discount_tax_compensation_invoiced":{"type":"number","description":"Discount tax compensation invoiced amount."},"discount_tax_compensation_refunded":{"type":"number","description":"Discount tax compensation refunded amount."},"hold_before_state":{"type":"string","description":"Hold before state."},"hold_before_status":{"type":"string","description":"Hold before status."},"increment_id":{"type":"string","description":"Increment ID."},"is_virtual":{"type":"integer","description":"Is-virtual flag value."},"order_currency_code":{"type":"string","description":"Order currency code."},"original_increment_id":{"type":"string","description":"Original increment ID."},"payment_authorization_amount":{"type":"number","description":"Payment authorization amount."},"payment_auth_expiration":{"type":"integer","description":"Payment authorization expiration date."},"protect_code":{"type":"string","description":"Protect code."},"quote_address_id":{"type":"integer","description":"Quote address ID."},"quote_id":{"type":"integer","description":"Quote ID."},"relation_child_id":{"type":"string","description":"Relation child ID."},"relation_child_real_id":{"type":"string","description":"Relation child real ID."},"relation_parent_id":{"type":"string","description":"Relation parent ID."},"relation_parent_real_id":{"type":"string","description":"Relation parent real ID."},"remote_ip":{"type":"string","description":"Remote IP address."},"shipping_amount":{"type":"number","description":"Shipping amount."},"shipping_canceled":{"type":"number","description":"Shipping canceled amount."},"shipping_description":{"type":"string","description":"Shipping description."},"shipping_discount_amount":{"type":"number","description":"Shipping discount amount."},"shipping_discount_tax_compensation_amount":{"type":"number","description":"Shipping discount tax compensation amount."},"shipping_incl_tax":{"type":"number","description":"Shipping including tax amount."},"shipping_invoiced":{"type":"number","description":"Shipping invoiced amount."},"shipping_refunded":{"type":"number","description":"Shipping refunded amount."},"shipping_tax_amount":{"type":"number","description":"Shipping tax amount."},"shipping_tax_refunded":{"type":"number","description":"Shipping tax refunded amount."},"state":{"type":"string","description":"State."},"status":{"type":"string","description":"Status."},"store_currency_code":{"type":"string","description":"Store currency code."},"store_id":{"type":"integer","description":"Store ID."},"store_name":{"type":"string","description":"Store name."},"store_to_base_rate":{"type":"number","description":"Store-to-base rate."},"store_to_order_rate":{"type":"number","description":"Store-to-order rate."},"subtotal":{"type":"number","description":"Subtotal."},"subtotal_canceled":{"type":"number","description":"Subtotal canceled amount."},"subtotal_incl_tax":{"type":"number","description":"Subtotal including tax amount."},"subtotal_invoiced":{"type":"number","description":"Subtotal invoiced amount."},"subtotal_refunded":{"type":"number","description":"Subtotal refunded amount."},"tax_amount":{"type":"number","description":"Tax amount."},"tax_canceled":{"type":"number","description":"Tax canceled amount."},"tax_invoiced":{"type":"number","description":"Tax invoiced amount."},"tax_refunded":{"type":"number","description":"Tax refunded amount."},"total_canceled":{"type":"number","description":"Total canceled."},"total_due":{"type":"number","description":"Total due."},"total_invoiced":{"type":"number","description":"Total invoiced amount."},"total_item_count":{"type":"integer","description":"Total item count."},"total_offline_refunded":{"type":"number","description":"Total offline refunded amount."},"total_online_refunded":{"type":"number","description":"Total online refunded amount."},"total_paid":{"type":"number","description":"Total paid."},"total_qty_ordered":{"type":"number","description":"Total quantity ordered."},"total_refunded":{"type":"number","description":"Total amount refunded."},"updated_at":{"type":"string","description":"Updated-at timestamp."},"weight":{"type":"number","description":"Weight."},"x_forwarded_for":{"type":"string","description":"X-Forwarded-For field value."},"items":{"type":"array","description":"Array of items.","items":{"$ref":"#/definitions/sales-data-order-item-interface"}},"billing_address":{"$ref":"#/definitions/sales-data-order-address-interface"},"payment":{"$ref":"#/definitions/sales-data-order-payment-interface"},"status_histories":{"type":"array","description":"Array of status histories.","items":{"$ref":"#/definitions/sales-data-order-status-history-interface"}},"extension_attributes":{"$ref":"#/definitions/sales-data-order-extension-interface"}},"required":["base_grand_total","customer_email","grand_total","items"]},"sales-data-order-item-interface":{"type":"object","description":"Order item interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"additional_data":{"type":"string","description":"Additional data."},"amount_refunded":{"type":"number","description":"Amount refunded."},"applied_rule_ids":{"type":"string","description":"Applied rule IDs."},"base_amount_refunded":{"type":"number","description":"Base amount refunded."},"base_cost":{"type":"number","description":"Base cost."},"base_discount_amount":{"type":"number","description":"Base discount amount."},"base_discount_invoiced":{"type":"number","description":"Base discount invoiced."},"base_discount_refunded":{"type":"number","description":"Base discount refunded."},"base_discount_tax_compensation_amount":{"type":"number","description":"Base discount tax compensation amount."},"base_discount_tax_compensation_invoiced":{"type":"number","description":"Base discount tax compensation invoiced."},"base_discount_tax_compensation_refunded":{"type":"number","description":"Base discount tax compensation refunded."},"base_original_price":{"type":"number","description":"Base original price."},"base_price":{"type":"number","description":"Base price."},"base_price_incl_tax":{"type":"number","description":"Base price including tax."},"base_row_invoiced":{"type":"number","description":"Base row invoiced."},"base_row_total":{"type":"number","description":"Base row total."},"base_row_total_incl_tax":{"type":"number","description":"Base row total including tax."},"base_tax_amount":{"type":"number","description":"Base tax amount."},"base_tax_before_discount":{"type":"number","description":"Base tax before discount."},"base_tax_invoiced":{"type":"number","description":"Base tax invoiced."},"base_tax_refunded":{"type":"number","description":"Base tax refunded."},"base_weee_tax_applied_amount":{"type":"number","description":"Base WEEE tax applied amount."},"base_weee_tax_applied_row_amnt":{"type":"number","description":"Base WEEE tax applied row amount."},"base_weee_tax_disposition":{"type":"number","description":"Base WEEE tax disposition."},"base_weee_tax_row_disposition":{"type":"number","description":"Base WEEE tax row disposition."},"created_at":{"type":"string","description":"Created-at timestamp."},"description":{"type":"string","description":"Description."},"discount_amount":{"type":"number","description":"Discount amount."},"discount_invoiced":{"type":"number","description":"Discount invoiced."},"discount_percent":{"type":"number","description":"Discount percent."},"discount_refunded":{"type":"number","description":"Discount refunded."},"event_id":{"type":"integer","description":"Event ID."},"ext_order_item_id":{"type":"string","description":"External order item ID."},"free_shipping":{"type":"integer","description":"Free-shipping flag value."},"gw_base_price":{"type":"number","description":"GW base price."},"gw_base_price_invoiced":{"type":"number","description":"GW base price invoiced."},"gw_base_price_refunded":{"type":"number","description":"GW base price refunded."},"gw_base_tax_amount":{"type":"number","description":"GW base tax amount."},"gw_base_tax_amount_invoiced":{"type":"number","description":"GW base tax amount invoiced."},"gw_base_tax_amount_refunded":{"type":"number","description":"GW base tax amount refunded."},"gw_id":{"type":"integer","description":"GW ID."},"gw_price":{"type":"number","description":"GW price."},"gw_price_invoiced":{"type":"number","description":"GW price invoiced."},"gw_price_refunded":{"type":"number","description":"GW price refunded."},"gw_tax_amount":{"type":"number","description":"GW tax amount."},"gw_tax_amount_invoiced":{"type":"number","description":"GW tax amount invoiced."},"gw_tax_amount_refunded":{"type":"number","description":"GW tax amount refunded."},"discount_tax_compensation_amount":{"type":"number","description":"Discount tax compensation amount."},"discount_tax_compensation_canceled":{"type":"number","description":"Discount tax compensation canceled."},"discount_tax_compensation_invoiced":{"type":"number","description":"Discount tax compensation invoiced."},"discount_tax_compensation_refunded":{"type":"number","description":"Discount tax compensation refunded."},"is_qty_decimal":{"type":"integer","description":"Is-quantity-decimal flag value."},"is_virtual":{"type":"integer","description":"Is-virtual flag value."},"item_id":{"type":"integer","description":"Item ID."},"locked_do_invoice":{"type":"integer","description":"Locked DO invoice flag value."},"locked_do_ship":{"type":"integer","description":"Locked DO ship flag value."},"name":{"type":"string","description":"Name."},"no_discount":{"type":"integer","description":"No-discount flag value."},"order_id":{"type":"integer","description":"Order ID."},"original_price":{"type":"number","description":"Original price."},"parent_item_id":{"type":"integer","description":"Parent item ID."},"price":{"type":"number","description":"Price."},"price_incl_tax":{"type":"number","description":"Price including tax."},"product_id":{"type":"integer","description":"Product ID."},"product_type":{"type":"string","description":"Product type."},"qty_backordered":{"type":"number","description":"Quantity backordered."},"qty_canceled":{"type":"number","description":"Quantity canceled."},"qty_invoiced":{"type":"number","description":"Quantity invoiced."},"qty_ordered":{"type":"number","description":"Quantity ordered."},"qty_refunded":{"type":"number","description":"Quantity refunded."},"qty_returned":{"type":"number","description":"Quantity returned."},"qty_shipped":{"type":"number","description":"Quantity shipped."},"quote_item_id":{"type":"integer","description":"Quote item ID."},"row_invoiced":{"type":"number","description":"Row invoiced."},"row_total":{"type":"number","description":"Row total."},"row_total_incl_tax":{"type":"number","description":"Row total including tax."},"row_weight":{"type":"number","description":"Row weight."},"sku":{"type":"string","description":"SKU."},"store_id":{"type":"integer","description":"Store ID."},"tax_amount":{"type":"number","description":"Tax amount."},"tax_before_discount":{"type":"number","description":"Tax before discount."},"tax_canceled":{"type":"number","description":"Tax canceled."},"tax_invoiced":{"type":"number","description":"Tax invoiced."},"tax_percent":{"type":"number","description":"Tax percent."},"tax_refunded":{"type":"number","description":"Tax refunded."},"updated_at":{"type":"string","description":"Updated-at timestamp."},"weee_tax_applied":{"type":"string","description":"WEEE tax applied."},"weee_tax_applied_amount":{"type":"number","description":"WEEE tax applied amount."},"weee_tax_applied_row_amount":{"type":"number","description":"WEEE tax applied row amount."},"weee_tax_disposition":{"type":"number","description":"WEEE tax disposition."},"weee_tax_row_disposition":{"type":"number","description":"WEEE tax row disposition."},"weight":{"type":"number","description":"Weight."},"parent_item":{"$ref":"#/definitions/sales-data-order-item-interface"},"product_option":{"$ref":"#/definitions/catalog-data-product-option-interface"},"extension_attributes":{"$ref":"#/definitions/sales-data-order-item-extension-interface"}},"required":["sku"]},"catalog-data-product-option-interface":{"type":"object","description":"Product option interface","properties":{"extension_attributes":{"$ref":"#/definitions/catalog-data-product-option-extension-interface"}}},"catalog-data-product-option-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Catalog\\Api\\Data\\ProductOptionInterface","properties":{"custom_options":{"type":"array","items":{"$ref":"#/definitions/catalog-data-custom-option-interface"}},"bundle_options":{"type":"array","items":{"$ref":"#/definitions/bundle-data-bundle-option-interface"}},"downloadable_option":{"$ref":"#/definitions/downloadable-data-downloadable-option-interface"},"giftcard_item_option":{"$ref":"#/definitions/gift-card-data-gift-card-option-interface"},"configurable_item_options":{"type":"array","items":{"$ref":"#/definitions/configurable-product-data-configurable-item-option-value-interface"}}}},"sales-data-order-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\OrderItemInterface","properties":{"gift_message":{"$ref":"#/definitions/gift-message-data-message-interface"},"gw_id":{"type":"string"},"gw_base_price":{"type":"string"},"gw_price":{"type":"string"},"gw_base_tax_amount":{"type":"string"},"gw_tax_amount":{"type":"string"},"gw_base_price_invoiced":{"type":"string"},"gw_price_invoiced":{"type":"string"},"gw_base_tax_amount_invoiced":{"type":"string"},"gw_tax_amount_invoiced":{"type":"string"},"gw_base_price_refunded":{"type":"string"},"gw_price_refunded":{"type":"string"},"gw_base_tax_amount_refunded":{"type":"string"},"gw_tax_amount_refunded":{"type":"string"}}},"sales-data-order-address-interface":{"type":"object","description":"Order address interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"address_type":{"type":"string","description":"Address type."},"city":{"type":"string","description":"City."},"company":{"type":"string","description":"Company."},"country_id":{"type":"string","description":"Country ID."},"customer_address_id":{"type":"integer","description":"Country address ID."},"customer_id":{"type":"integer","description":"Customer ID."},"email":{"type":"string","description":"Email address."},"entity_id":{"type":"integer","description":"Order address ID."},"fax":{"type":"string","description":"Fax number."},"firstname":{"type":"string","description":"First name."},"lastname":{"type":"string","description":"Last name."},"middlename":{"type":"string","description":"Middle name."},"parent_id":{"type":"integer","description":"Parent ID."},"postcode":{"type":"string","description":"Postal code."},"prefix":{"type":"string","description":"Prefix."},"region":{"type":"string","description":"Region."},"region_code":{"type":"string","description":"Region code."},"region_id":{"type":"integer","description":"Region ID."},"street":{"type":"array","description":"Array of any street values. Otherwise, null.","items":{"type":"string"}},"suffix":{"type":"string","description":"Suffix."},"telephone":{"type":"string","description":"Telephone number."},"vat_id":{"type":"string","description":"VAT ID."},"vat_is_valid":{"type":"integer","description":"VAT-is-valid flag value."},"vat_request_date":{"type":"string","description":"VAT request date."},"vat_request_id":{"type":"string","description":"VAT request ID."},"vat_request_success":{"type":"integer","description":"VAT-request-success flag value."},"extension_attributes":{"$ref":"#/definitions/sales-data-order-address-extension-interface"}},"required":["address_type","city","country_id","firstname","lastname","postcode","telephone"]},"sales-data-order-address-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\OrderAddressInterface"},"sales-data-order-payment-interface":{"type":"object","description":"Order payment interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"account_status":{"type":"string","description":"Account status."},"additional_data":{"type":"string","description":"Additional data."},"additional_information":{"type":"array","description":"Array of additional information.","items":{"type":"string"}},"address_status":{"type":"string","description":"Address status."},"amount_authorized":{"type":"number","description":"Amount authorized."},"amount_canceled":{"type":"number","description":"Amount canceled."},"amount_ordered":{"type":"number","description":"Amount ordered."},"amount_paid":{"type":"number","description":"Amount paid."},"amount_refunded":{"type":"number","description":"Amount refunded."},"anet_trans_method":{"type":"string","description":"Anet transaction method."},"base_amount_authorized":{"type":"number","description":"Base amount authorized."},"base_amount_canceled":{"type":"number","description":"Base amount canceled."},"base_amount_ordered":{"type":"number","description":"Base amount ordered."},"base_amount_paid":{"type":"number","description":"Base amount paid."},"base_amount_paid_online":{"type":"number","description":"Base amount paid online."},"base_amount_refunded":{"type":"number","description":"Base amount refunded."},"base_amount_refunded_online":{"type":"number","description":"Base amount refunded online."},"base_shipping_amount":{"type":"number","description":"Base shipping amount."},"base_shipping_captured":{"type":"number","description":"Base shipping captured amount."},"base_shipping_refunded":{"type":"number","description":"Base shipping refunded amount."},"cc_approval":{"type":"string","description":"Credit card approval."},"cc_avs_status":{"type":"string","description":"Credit card avs status."},"cc_cid_status":{"type":"string","description":"Credit card CID status."},"cc_debug_request_body":{"type":"string","description":"Credit card debug request body."},"cc_debug_response_body":{"type":"string","description":"Credit card debug response body."},"cc_debug_response_serialized":{"type":"string","description":"Credit card debug response serialized."},"cc_exp_month":{"type":"string","description":"Credit card expiration month."},"cc_exp_year":{"type":"string","description":"Credit card expiration year."},"cc_last4":{"type":"string","description":"Last four digits of the credit card."},"cc_number_enc":{"type":"string","description":"Encrypted credit card number."},"cc_owner":{"type":"string","description":"Credit card number."},"cc_secure_verify":{"type":"string","description":"Credit card secure verify."},"cc_ss_issue":{"type":"string","description":"Credit card SS issue."},"cc_ss_start_month":{"type":"string","description":"Credit card SS start month."},"cc_ss_start_year":{"type":"string","description":"Credit card SS start year."},"cc_status":{"type":"string","description":"Credit card status."},"cc_status_description":{"type":"string","description":"Credit card status description."},"cc_trans_id":{"type":"string","description":"Credit card transaction ID."},"cc_type":{"type":"string","description":"Credit card type."},"echeck_account_name":{"type":"string","description":"eCheck account name."},"echeck_account_type":{"type":"string","description":"eCheck account type."},"echeck_bank_name":{"type":"string","description":"eCheck bank name."},"echeck_routing_number":{"type":"string","description":"eCheck routing number."},"echeck_type":{"type":"string","description":"eCheck type."},"entity_id":{"type":"integer","description":"Entity ID."},"last_trans_id":{"type":"string","description":"Last transaction ID."},"method":{"type":"string","description":"Method."},"parent_id":{"type":"integer","description":"Parent ID."},"po_number":{"type":"string","description":"PO number."},"protection_eligibility":{"type":"string","description":"Protection eligibility."},"quote_payment_id":{"type":"integer","description":"Quote payment ID."},"shipping_amount":{"type":"number","description":"Shipping amount."},"shipping_captured":{"type":"number","description":"Shipping captured."},"shipping_refunded":{"type":"number","description":"Shipping refunded."},"extension_attributes":{"$ref":"#/definitions/sales-data-order-payment-extension-interface"}},"required":["account_status","additional_information","cc_last4","method"]},"sales-data-order-payment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\OrderPaymentInterface","properties":{"vault_payment_token":{"$ref":"#/definitions/vault-data-payment-token-interface"}}},"vault-data-payment-token-interface":{"type":"object","description":"Gateway vault payment token interface.","properties":{"entity_id":{"type":"integer","description":"Entity ID."},"customer_id":{"type":"integer","description":"Customer ID."},"public_hash":{"type":"string","description":"Public hash"},"payment_method_code":{"type":"string","description":"Payment method code"},"type":{"type":"string","description":"Type"},"created_at":{"type":"string","description":"Token creation timestamp"},"expires_at":{"type":"string","description":"Token expiration timestamp"},"gateway_token":{"type":"string","description":"Gateway token ID"},"token_details":{"type":"string","description":"Token details"},"is_active":{"type":"boolean","description":"Is active."},"is_visible":{"type":"boolean","description":"Is visible."}},"required":["public_hash","payment_method_code","type","gateway_token","token_details","is_active","is_visible"]},"sales-data-order-status-history-interface":{"type":"object","description":"Order status history interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"comment":{"type":"string","description":"Comment."},"created_at":{"type":"string","description":"Created-at timestamp."},"entity_id":{"type":"integer","description":"Order status history ID."},"entity_name":{"type":"string","description":"Entity name."},"is_customer_notified":{"type":"integer","description":"Is-customer-notified flag value."},"is_visible_on_front":{"type":"integer","description":"Is-visible-on-storefront flag value."},"parent_id":{"type":"integer","description":"Parent ID."},"status":{"type":"string","description":"Status."},"extension_attributes":{"$ref":"#/definitions/sales-data-order-status-history-extension-interface"}},"required":["comment","is_customer_notified","is_visible_on_front","parent_id"]},"sales-data-order-status-history-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\OrderStatusHistoryInterface"},"sales-data-order-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\OrderInterface","properties":{"shipping_assignments":{"type":"array","items":{"$ref":"#/definitions/sales-data-shipping-assignment-interface"}},"base_customer_balance_amount":{"type":"number"},"customer_balance_amount":{"type":"number"},"base_customer_balance_invoiced":{"type":"number"},"customer_balance_invoiced":{"type":"number"},"base_customer_balance_refunded":{"type":"number"},"customer_balance_refunded":{"type":"number"},"base_customer_balance_total_refunded":{"type":"number"},"customer_balance_total_refunded":{"type":"number"},"gift_cards":{"type":"array","items":{"$ref":"#/definitions/gift-card-account-data-gift-card-interface"}},"base_gift_cards_amount":{"type":"number"},"gift_cards_amount":{"type":"number"},"base_gift_cards_invoiced":{"type":"number"},"gift_cards_invoiced":{"type":"number"},"base_gift_cards_refunded":{"type":"number"},"gift_cards_refunded":{"type":"number"},"applied_taxes":{"type":"array","items":{"$ref":"#/definitions/tax-data-order-tax-details-applied-tax-interface"}},"item_applied_taxes":{"type":"array","items":{"$ref":"#/definitions/tax-data-order-tax-details-item-interface"}},"converting_from_quote":{"type":"boolean"},"gift_message":{"$ref":"#/definitions/gift-message-data-message-interface"},"gw_id":{"type":"string"},"gw_allow_gift_receipt":{"type":"string"},"gw_add_card":{"type":"string"},"gw_base_price":{"type":"string"},"gw_price":{"type":"string"},"gw_items_base_price":{"type":"string"},"gw_items_price":{"type":"string"},"gw_card_base_price":{"type":"string"},"gw_card_price":{"type":"string"},"gw_base_tax_amount":{"type":"string"},"gw_tax_amount":{"type":"string"},"gw_items_base_tax_amount":{"type":"string"},"gw_items_tax_amount":{"type":"string"},"gw_card_base_tax_amount":{"type":"string"},"gw_card_tax_amount":{"type":"string"},"gw_base_price_incl_tax":{"type":"string"},"gw_price_incl_tax":{"type":"string"},"gw_items_base_price_incl_tax":{"type":"string"},"gw_items_price_incl_tax":{"type":"string"},"gw_card_base_price_incl_tax":{"type":"string"},"gw_card_price_incl_tax":{"type":"string"},"gw_base_price_invoiced":{"type":"string"},"gw_price_invoiced":{"type":"string"},"gw_items_base_price_invoiced":{"type":"string"},"gw_items_price_invoiced":{"type":"string"},"gw_card_base_price_invoiced":{"type":"string"},"gw_card_price_invoiced":{"type":"string"},"gw_base_tax_amount_invoiced":{"type":"string"},"gw_tax_amount_invoiced":{"type":"string"},"gw_items_base_tax_invoiced":{"type":"string"},"gw_items_tax_invoiced":{"type":"string"},"gw_card_base_tax_invoiced":{"type":"string"},"gw_card_tax_invoiced":{"type":"string"},"gw_base_price_refunded":{"type":"string"},"gw_price_refunded":{"type":"string"},"gw_items_base_price_refunded":{"type":"string"},"gw_items_price_refunded":{"type":"string"},"gw_card_base_price_refunded":{"type":"string"},"gw_card_price_refunded":{"type":"string"},"gw_base_tax_amount_refunded":{"type":"string"},"gw_tax_amount_refunded":{"type":"string"},"gw_items_base_tax_refunded":{"type":"string"},"gw_items_tax_refunded":{"type":"string"},"gw_card_base_tax_refunded":{"type":"string"},"gw_card_tax_refunded":{"type":"string"}}},"sales-data-shipping-assignment-interface":{"type":"object","description":"Interface ShippingAssignmentInterface","properties":{"shipping":{"$ref":"#/definitions/sales-data-shipping-interface"},"items":{"type":"array","description":"Order items of shipping assignment","items":{"$ref":"#/definitions/sales-data-order-item-interface"}},"stock_id":{"type":"integer","description":"Stock id"},"extension_attributes":{"$ref":"#/definitions/sales-data-shipping-assignment-extension-interface"}},"required":["shipping","items"]},"sales-data-shipping-interface":{"type":"object","description":"Interface ShippingInterface","properties":{"address":{"$ref":"#/definitions/sales-data-order-address-interface"},"method":{"type":"string","description":"Shipping method"},"total":{"$ref":"#/definitions/sales-data-total-interface"},"extension_attributes":{"$ref":"#/definitions/sales-data-shipping-extension-interface"}}},"sales-data-total-interface":{"type":"object","description":"Interface TotalInterface","properties":{"base_shipping_amount":{"type":"number","description":"Base shipping amount."},"base_shipping_canceled":{"type":"number","description":"Base shipping canceled."},"base_shipping_discount_amount":{"type":"number","description":"Base shipping discount amount."},"base_shipping_discount_tax_compensation_amnt":{"type":"number","description":"Base shipping discount tax compensation amount."},"base_shipping_incl_tax":{"type":"number","description":"Base shipping including tax."},"base_shipping_invoiced":{"type":"number","description":"Base shipping invoiced."},"base_shipping_refunded":{"type":"number","description":"Base shipping refunded."},"base_shipping_tax_amount":{"type":"number","description":"Base shipping tax amount."},"base_shipping_tax_refunded":{"type":"number","description":"Base shipping tax refunded."},"shipping_amount":{"type":"number","description":"Shipping amount."},"shipping_canceled":{"type":"number","description":"Shipping canceled amount."},"shipping_discount_amount":{"type":"number","description":"Shipping discount amount."},"shipping_discount_tax_compensation_amount":{"type":"number","description":"Shipping discount tax compensation amount."},"shipping_incl_tax":{"type":"number","description":"Shipping including tax amount."},"shipping_invoiced":{"type":"number","description":"Shipping invoiced amount."},"shipping_refunded":{"type":"number","description":"Shipping refunded amount."},"shipping_tax_amount":{"type":"number","description":"Shipping tax amount."},"shipping_tax_refunded":{"type":"number","description":"Shipping tax refunded amount."},"extension_attributes":{"$ref":"#/definitions/sales-data-total-extension-interface"}}},"sales-data-total-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\TotalInterface"},"sales-data-shipping-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShippingInterface"},"sales-data-shipping-assignment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShippingAssignmentInterface"},"gift-card-account-data-gift-card-interface":{"type":"object","description":"Gift Card data","properties":{"id":{"type":"integer","description":"Id"},"code":{"type":"string","description":"Code"},"amount":{"type":"number","description":"Amount"},"base_amount":{"type":"number","description":"Base Amount"}},"required":["id","code","amount","base_amount"]},"tax-data-order-tax-details-applied-tax-interface":{"type":"object","description":"Interface OrderTaxDetailsAppliedTaxInterface","properties":{"code":{"type":"string","description":"Code"},"title":{"type":"string","description":"Title"},"percent":{"type":"number","description":"Tax Percent"},"amount":{"type":"number","description":"Tax amount"},"base_amount":{"type":"number","description":"Tax amount in base currency"},"extension_attributes":{"$ref":"#/definitions/tax-data-order-tax-details-applied-tax-extension-interface"}},"required":["amount","base_amount"]},"tax-data-order-tax-details-applied-tax-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Tax\\Api\\Data\\OrderTaxDetailsAppliedTaxInterface","properties":{"rates":{"type":"array","items":{"$ref":"#/definitions/tax-data-applied-tax-rate-interface"}}}},"tax-data-applied-tax-rate-interface":{"type":"object","description":"Applied tax rate interface.","properties":{"code":{"type":"string","description":"Code"},"title":{"type":"string","description":"Title"},"percent":{"type":"number","description":"Tax Percent"},"extension_attributes":{"$ref":"#/definitions/tax-data-applied-tax-rate-extension-interface"}}},"tax-data-applied-tax-rate-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Tax\\Api\\Data\\AppliedTaxRateInterface"},"tax-data-order-tax-details-item-interface":{"type":"object","description":"Interface OrderTaxDetailsItemInterface","properties":{"type":{"type":"string","description":"Type (shipping, product, weee, gift wrapping, etc)"},"item_id":{"type":"integer","description":"Item id if this item is a product"},"associated_item_id":{"type":"integer","description":"Associated item id if this item is associated with another item, null otherwise"},"applied_taxes":{"type":"array","description":"Applied taxes","items":{"$ref":"#/definitions/tax-data-order-tax-details-applied-tax-interface"}},"extension_attributes":{"$ref":"#/definitions/tax-data-order-tax-details-item-extension-interface"}}},"tax-data-order-tax-details-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Tax\\Api\\Data\\OrderTaxDetailsItemInterface"},"sales-data-order-search-result-interface":{"type":"object","description":"Order search result interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-order-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-order-status-history-search-result-interface":{"type":"object","description":"Order status history search result interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-order-status-history-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-order-item-search-result-interface":{"type":"object","description":"Order item search result interface. An order is a document that a web store issues to a customer. Magento generates a sales order that lists the product items, billing and shipping addresses, and shipping and payment methods. A corresponding external document, known as a purchase order, is emailed to the customer.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-order-item-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-invoice-interface":{"type":"object","description":"Invoice interface. An invoice is a record of the receipt of payment for an order.","properties":{"base_currency_code":{"type":"string","description":"Base currency code."},"base_discount_amount":{"type":"number","description":"Base discount amount."},"base_grand_total":{"type":"number","description":"Base grand total."},"base_discount_tax_compensation_amount":{"type":"number","description":"Base discount tax compensation amount."},"base_shipping_amount":{"type":"number","description":"Base shipping amount."},"base_shipping_discount_tax_compensation_amnt":{"type":"number","description":"Base shipping discount tax compensation amount."},"base_shipping_incl_tax":{"type":"number","description":"Base shipping including tax."},"base_shipping_tax_amount":{"type":"number","description":"Base shipping tax amount."},"base_subtotal":{"type":"number","description":"Base subtotal."},"base_subtotal_incl_tax":{"type":"number","description":"Base subtotal including tax."},"base_tax_amount":{"type":"number","description":"Base tax amount."},"base_total_refunded":{"type":"number","description":"Base total refunded."},"base_to_global_rate":{"type":"number","description":"Base-to-global rate."},"base_to_order_rate":{"type":"number","description":"Base-to-order rate."},"billing_address_id":{"type":"integer","description":"Billing address ID."},"can_void_flag":{"type":"integer","description":"Can void flag value."},"created_at":{"type":"string","description":"Created-at timestamp."},"discount_amount":{"type":"number","description":"Discount amount."},"discount_description":{"type":"string","description":"Discount description."},"email_sent":{"type":"integer","description":"Email-sent flag value."},"entity_id":{"type":"integer","description":"Invoice ID."},"global_currency_code":{"type":"string","description":"Global currency code."},"grand_total":{"type":"number","description":"Grand total."},"discount_tax_compensation_amount":{"type":"number","description":"Discount tax compensation amount."},"increment_id":{"type":"string","description":"Increment ID."},"is_used_for_refund":{"type":"integer","description":"Is-used-for-refund flag value."},"order_currency_code":{"type":"string","description":"Order currency code."},"order_id":{"type":"integer","description":"Order ID."},"shipping_address_id":{"type":"integer","description":"Shipping address ID."},"shipping_amount":{"type":"number","description":"Shipping amount."},"shipping_discount_tax_compensation_amount":{"type":"number","description":"Shipping discount tax compensation amount."},"shipping_incl_tax":{"type":"number","description":"Shipping including tax."},"shipping_tax_amount":{"type":"number","description":"Shipping tax amount."},"state":{"type":"integer","description":"State."},"store_currency_code":{"type":"string","description":"Store currency code."},"store_id":{"type":"integer","description":"Store ID."},"store_to_base_rate":{"type":"number","description":"Store-to-base rate."},"store_to_order_rate":{"type":"number","description":"Store-to-order rate."},"subtotal":{"type":"number","description":"Subtotal."},"subtotal_incl_tax":{"type":"number","description":"Subtotal including tax."},"tax_amount":{"type":"number","description":"Tax amount."},"total_qty":{"type":"number","description":"Total quantity."},"transaction_id":{"type":"string","description":"Transaction ID."},"updated_at":{"type":"string","description":"Updated-at timestamp."},"items":{"type":"array","description":"Array of invoice items.","items":{"$ref":"#/definitions/sales-data-invoice-item-interface"}},"comments":{"type":"array","description":"Array of any invoice comments. Otherwise, null.","items":{"$ref":"#/definitions/sales-data-invoice-comment-interface"}},"extension_attributes":{"$ref":"#/definitions/sales-data-invoice-extension-interface"}},"required":["order_id","total_qty","items"]},"sales-data-invoice-item-interface":{"type":"object","description":"Invoice item interface. An invoice is a record of the receipt of payment for an order. An invoice item is a purchased item in an invoice.","properties":{"additional_data":{"type":"string","description":"Additional data."},"base_cost":{"type":"number","description":"Base cost."},"base_discount_amount":{"type":"number","description":"Base discount amount."},"base_discount_tax_compensation_amount":{"type":"number","description":"Base discount tax compensation amount."},"base_price":{"type":"number","description":"Base price."},"base_price_incl_tax":{"type":"number","description":"Base price including tax."},"base_row_total":{"type":"number","description":"Base row total."},"base_row_total_incl_tax":{"type":"number","description":"Base row total including tax."},"base_tax_amount":{"type":"number","description":"Base tax amount."},"description":{"type":"string","description":"Description."},"discount_amount":{"type":"number","description":"Discount amount."},"entity_id":{"type":"integer","description":"Invoice item ID."},"discount_tax_compensation_amount":{"type":"number","description":"Discount tax compensation amount."},"name":{"type":"string","description":"Name."},"parent_id":{"type":"integer","description":"Parent ID."},"price":{"type":"number","description":"Price."},"price_incl_tax":{"type":"number","description":"Price including tax."},"product_id":{"type":"integer","description":"Product ID."},"row_total":{"type":"number","description":"Row total."},"row_total_incl_tax":{"type":"number","description":"Row total including tax."},"sku":{"type":"string","description":"SKU."},"tax_amount":{"type":"number","description":"Tax amount."},"extension_attributes":{"$ref":"#/definitions/sales-data-invoice-item-extension-interface"},"order_item_id":{"type":"integer","description":"Order item ID."},"qty":{"type":"number","description":"Quantity."}},"required":["sku","order_item_id","qty"]},"sales-data-invoice-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\InvoiceItemInterface"},"sales-data-invoice-comment-interface":{"type":"object","description":"Invoice comment interface. An invoice is a record of the receipt of payment for an order. An invoice can include comments that detail the invoice history.","properties":{"is_customer_notified":{"type":"integer","description":"Is-customer-notified flag value."},"parent_id":{"type":"integer","description":"Parent ID."},"extension_attributes":{"$ref":"#/definitions/sales-data-invoice-comment-extension-interface"},"comment":{"type":"string","description":"Comment."},"is_visible_on_front":{"type":"integer","description":"Is-visible-on-storefront flag value."},"created_at":{"type":"string","description":"Created-at timestamp."},"entity_id":{"type":"integer","description":"Invoice ID."}},"required":["is_customer_notified","parent_id","comment","is_visible_on_front"]},"sales-data-invoice-comment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\InvoiceCommentInterface"},"sales-data-invoice-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\InvoiceInterface","properties":{"base_customer_balance_amount":{"type":"number"},"customer_balance_amount":{"type":"number"},"base_gift_cards_amount":{"type":"number"},"gift_cards_amount":{"type":"number"},"gw_base_price":{"type":"string"},"gw_price":{"type":"string"},"gw_items_base_price":{"type":"string"},"gw_items_price":{"type":"string"},"gw_card_base_price":{"type":"string"},"gw_card_price":{"type":"string"},"gw_base_tax_amount":{"type":"string"},"gw_tax_amount":{"type":"string"},"gw_items_base_tax_amount":{"type":"string"},"gw_items_tax_amount":{"type":"string"},"gw_card_base_tax_amount":{"type":"string"},"gw_card_tax_amount":{"type":"string"},"invoice_api_test_attribute":{"$ref":"#/definitions/user-data-user-interface"}}},"sales-data-invoice-search-result-interface":{"type":"object","description":"Invoice search result interface. An invoice is a record of the receipt of payment for an order.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-invoice-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-invoice-comment-search-result-interface":{"type":"object","description":"Invoice comment search result interface. An invoice is a record of the receipt of payment for an order. An invoice can include comments that detail the invoice history.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-invoice-comment-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-creditmemo-item-creation-interface":{"type":"object","description":"Interface CreditmemoItemCreationInterface","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-creditmemo-item-creation-extension-interface"},"order_item_id":{"type":"integer","description":"Order item ID."},"qty":{"type":"number","description":"Quantity."}},"required":["order_item_id","qty"]},"sales-data-creditmemo-item-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\CreditmemoItemCreationInterface"},"sales-data-creditmemo-comment-creation-interface":{"type":"object","description":"Interface CreditmemoCommentCreationInterface","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-creditmemo-comment-creation-extension-interface"},"comment":{"type":"string","description":"Comment."},"is_visible_on_front":{"type":"integer","description":"Is-visible-on-storefront flag value."}},"required":["comment","is_visible_on_front"]},"sales-data-creditmemo-comment-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\CreditmemoCommentCreationInterface"},"sales-data-creditmemo-creation-arguments-interface":{"type":"object","description":"Interface CreditmemoCreationArgumentsInterface","properties":{"shipping_amount":{"type":"number","description":"Credit memo shipping amount."},"adjustment_positive":{"type":"number","description":"Credit memo positive adjustment."},"adjustment_negative":{"type":"number","description":"Credit memo negative adjustment."},"extension_attributes":{"$ref":"#/definitions/sales-data-creditmemo-creation-arguments-extension-interface"}}},"sales-data-creditmemo-creation-arguments-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\CreditmemoCreationArgumentsInterface","properties":{"return_to_stock_items":{"type":"array","items":{"type":"integer"}}}},"sales-data-creditmemo-comment-search-result-interface":{"type":"object","description":"Credit memo comment search result interface. After a customer places and pays for an order and an invoice has been issued, the merchant can create a credit memo to refund all or part of the amount paid for any returned or undelivered items. The memo restores funds to the customer account so that the customer can make future purchases. A credit memo usually includes comments that detail why the credit memo amount was credited to the customer.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-creditmemo-comment-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-creditmemo-comment-interface":{"type":"object","description":"Credit memo comment interface. After a customer places and pays for an order and an invoice has been issued, the merchant can create a credit memo to refund all or part of the amount paid for any returned or undelivered items. The memo restores funds to the customer account so that the customer can make future purchases. A credit memo usually includes comments that detail why the credit memo amount was credited to the customer.","properties":{"comment":{"type":"string","description":"Comment."},"created_at":{"type":"string","description":"Created-at timestamp."},"entity_id":{"type":"integer","description":"Credit memo ID."},"is_customer_notified":{"type":"integer","description":"Is-customer-notified flag value."},"is_visible_on_front":{"type":"integer","description":"Is-visible-on-storefront flag value."},"parent_id":{"type":"integer","description":"Parent ID."},"extension_attributes":{"$ref":"#/definitions/sales-data-creditmemo-comment-extension-interface"}},"required":["comment","is_customer_notified","is_visible_on_front","parent_id"]},"sales-data-creditmemo-comment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\CreditmemoCommentInterface"},"sales-data-creditmemo-interface":{"type":"object","description":"Credit memo interface. After a customer places and pays for an order and an invoice has been issued, the merchant can create a credit memo to refund all or part of the amount paid for any returned or undelivered items. The memo restores funds to the customer account so that the customer can make future purchases.","properties":{"adjustment":{"type":"number","description":"Credit memo adjustment."},"adjustment_negative":{"type":"number","description":"Credit memo negative adjustment."},"adjustment_positive":{"type":"number","description":"Credit memo positive adjustment."},"base_adjustment":{"type":"number","description":"Credit memo base adjustment."},"base_adjustment_negative":{"type":"number","description":"Credit memo negative base adjustment."},"base_adjustment_positive":{"type":"number","description":"Credit memo positive base adjustment."},"base_currency_code":{"type":"string","description":"Credit memo base currency code."},"base_discount_amount":{"type":"number","description":"Credit memo base discount amount."},"base_grand_total":{"type":"number","description":"Credit memo base grand total."},"base_discount_tax_compensation_amount":{"type":"number","description":"Credit memo base discount tax compensation amount."},"base_shipping_amount":{"type":"number","description":"Credit memo base shipping amount."},"base_shipping_discount_tax_compensation_amnt":{"type":"number","description":"Credit memo base shipping discount tax compensation amount."},"base_shipping_incl_tax":{"type":"number","description":"Credit memo base shipping including tax."},"base_shipping_tax_amount":{"type":"number","description":"Credit memo base shipping tax amount."},"base_subtotal":{"type":"number","description":"Credit memo base subtotal."},"base_subtotal_incl_tax":{"type":"number","description":"Credit memo base subtotal including tax."},"base_tax_amount":{"type":"number","description":"Credit memo base tax amount."},"base_to_global_rate":{"type":"number","description":"Credit memo base-to-global rate."},"base_to_order_rate":{"type":"number","description":"Credit memo base-to-order rate."},"billing_address_id":{"type":"integer","description":"Credit memo billing address ID."},"created_at":{"type":"string","description":"Credit memo created-at timestamp."},"creditmemo_status":{"type":"integer","description":"Credit memo status."},"discount_amount":{"type":"number","description":"Credit memo discount amount."},"discount_description":{"type":"string","description":"Credit memo discount description."},"email_sent":{"type":"integer","description":"Credit memo email sent flag value."},"entity_id":{"type":"integer","description":"Credit memo ID."},"global_currency_code":{"type":"string","description":"Credit memo global currency code."},"grand_total":{"type":"number","description":"Credit memo grand total."},"discount_tax_compensation_amount":{"type":"number","description":"Credit memo discount tax compensation amount."},"increment_id":{"type":"string","description":"Credit memo increment ID."},"invoice_id":{"type":"integer","description":"Credit memo invoice ID."},"order_currency_code":{"type":"string","description":"Credit memo order currency code."},"order_id":{"type":"integer","description":"Credit memo order ID."},"shipping_address_id":{"type":"integer","description":"Credit memo shipping address ID."},"shipping_amount":{"type":"number","description":"Credit memo shipping amount."},"shipping_discount_tax_compensation_amount":{"type":"number","description":"Credit memo shipping discount tax compensation amount."},"shipping_incl_tax":{"type":"number","description":"Credit memo shipping including tax."},"shipping_tax_amount":{"type":"number","description":"Credit memo shipping tax amount."},"state":{"type":"integer","description":"Credit memo state."},"store_currency_code":{"type":"string","description":"Credit memo store currency code."},"store_id":{"type":"integer","description":"Credit memo store ID."},"store_to_base_rate":{"type":"number","description":"Credit memo store-to-base rate."},"store_to_order_rate":{"type":"number","description":"Credit memo store-to-order rate."},"subtotal":{"type":"number","description":"Credit memo subtotal."},"subtotal_incl_tax":{"type":"number","description":"Credit memo subtotal including tax."},"tax_amount":{"type":"number","description":"Credit memo tax amount."},"transaction_id":{"type":"string","description":"Credit memo transaction ID."},"updated_at":{"type":"string","description":"Credit memo updated-at timestamp."},"items":{"type":"array","description":"Array of credit memo items.","items":{"$ref":"#/definitions/sales-data-creditmemo-item-interface"}},"comments":{"type":"array","description":"Array of any credit memo comments. Otherwise, null.","items":{"$ref":"#/definitions/sales-data-creditmemo-comment-interface"}},"extension_attributes":{"$ref":"#/definitions/sales-data-creditmemo-extension-interface"}},"required":["order_id","items"]},"sales-data-creditmemo-item-interface":{"type":"object","description":"Credit memo item interface. After a customer places and pays for an order and an invoice has been issued, the merchant can create a credit memo to refund all or part of the amount paid for any returned or undelivered items. The memo restores funds to the customer account so that the customer can make future purchases. A credit memo item is an invoiced item for which a merchant creates a credit memo.","properties":{"additional_data":{"type":"string","description":"Additional data."},"base_cost":{"type":"number","description":"The base cost for a credit memo item."},"base_discount_amount":{"type":"number","description":"The base discount amount for a credit memo item."},"base_discount_tax_compensation_amount":{"type":"number","description":"The base discount tax compensation amount for a credit memo item."},"base_price":{"type":"number","description":"The base price for a credit memo item."},"base_price_incl_tax":{"type":"number","description":"Base price including tax."},"base_row_total":{"type":"number","description":"Base row total."},"base_row_total_incl_tax":{"type":"number","description":"Base row total including tax."},"base_tax_amount":{"type":"number","description":"Base tax amount."},"base_weee_tax_applied_amount":{"type":"number","description":"Base WEEE tax applied amount."},"base_weee_tax_applied_row_amnt":{"type":"number","description":"Base WEEE tax applied row amount."},"base_weee_tax_disposition":{"type":"number","description":"Base WEEE tax disposition."},"base_weee_tax_row_disposition":{"type":"number","description":"Base WEEE tax row disposition."},"description":{"type":"string","description":"Description."},"discount_amount":{"type":"number","description":"Discount amount."},"entity_id":{"type":"integer","description":"Credit memo item ID."},"discount_tax_compensation_amount":{"type":"number","description":"Discount tax compensation amount."},"name":{"type":"string","description":"Name."},"order_item_id":{"type":"integer","description":"Order item ID."},"parent_id":{"type":"integer","description":"Parent ID."},"price":{"type":"number","description":"Price."},"price_incl_tax":{"type":"number","description":"Price including tax."},"product_id":{"type":"integer","description":"Product ID."},"qty":{"type":"number","description":"Quantity."},"row_total":{"type":"number","description":"Row total."},"row_total_incl_tax":{"type":"number","description":"Row total including tax."},"sku":{"type":"string","description":"SKU."},"tax_amount":{"type":"number","description":"Tax amount."},"weee_tax_applied":{"type":"string","description":"WEEE tax applied."},"weee_tax_applied_amount":{"type":"number","description":"WEEE tax applied amount."},"weee_tax_applied_row_amount":{"type":"number","description":"WEEE tax applied row amount."},"weee_tax_disposition":{"type":"number","description":"WEEE tax disposition."},"weee_tax_row_disposition":{"type":"number","description":"WEEE tax row disposition."},"extension_attributes":{"$ref":"#/definitions/sales-data-creditmemo-item-extension-interface"}},"required":["base_cost","base_price","entity_id","order_item_id","qty"]},"sales-data-creditmemo-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\CreditmemoItemInterface"},"sales-data-creditmemo-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\CreditmemoInterface","properties":{"base_customer_balance_amount":{"type":"number"},"customer_balance_amount":{"type":"number"},"base_gift_cards_amount":{"type":"number"},"gift_cards_amount":{"type":"number"},"gw_base_price":{"type":"string"},"gw_price":{"type":"string"},"gw_items_base_price":{"type":"string"},"gw_items_price":{"type":"string"},"gw_card_base_price":{"type":"string"},"gw_card_price":{"type":"string"},"gw_base_tax_amount":{"type":"string"},"gw_tax_amount":{"type":"string"},"gw_items_base_tax_amount":{"type":"string"},"gw_items_tax_amount":{"type":"string"},"gw_card_base_tax_amount":{"type":"string"},"gw_card_tax_amount":{"type":"string"}}},"sales-data-creditmemo-search-result-interface":{"type":"object","description":"Credit memo search result interface. After a customer places and pays for an order and an invoice has been issued, the merchant can create a credit memo to refund all or part of the amount paid for any returned or undelivered items. The memo restores funds to the customer account so that the customer can make future purchases.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-creditmemo-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-shipment-interface":{"type":"object","description":"Shipment interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package.","properties":{"billing_address_id":{"type":"integer","description":"Billing address ID."},"created_at":{"type":"string","description":"Created-at timestamp."},"customer_id":{"type":"integer","description":"Customer ID."},"email_sent":{"type":"integer","description":"Email-sent flag value."},"entity_id":{"type":"integer","description":"Shipment ID."},"increment_id":{"type":"string","description":"Increment ID."},"order_id":{"type":"integer","description":"Order ID."},"packages":{"type":"array","description":"Array of packages, if any. Otherwise, null.","items":{"$ref":"#/definitions/sales-data-shipment-package-interface"}},"shipment_status":{"type":"integer","description":"Shipment status."},"shipping_address_id":{"type":"integer","description":"Shipping address ID."},"shipping_label":{"type":"string","description":"Shipping label."},"store_id":{"type":"integer","description":"Store ID."},"total_qty":{"type":"number","description":"Total quantity."},"total_weight":{"type":"number","description":"Total weight."},"updated_at":{"type":"string","description":"Updated-at timestamp."},"items":{"type":"array","description":"Array of items.","items":{"$ref":"#/definitions/sales-data-shipment-item-interface"}},"tracks":{"type":"array","description":"Array of tracks.","items":{"$ref":"#/definitions/sales-data-shipment-track-interface"}},"comments":{"type":"array","description":"Array of comments.","items":{"$ref":"#/definitions/sales-data-shipment-comment-interface"}},"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-extension-interface"}},"required":["order_id","items","tracks","comments"]},"sales-data-shipment-package-interface":{"type":"object","description":"Shipment package interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package.","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-package-extension-interface"}}},"sales-data-shipment-package-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentPackageInterface"},"sales-data-shipment-item-interface":{"type":"object","description":"Shipment item interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package. A product is an item in a shipment.","properties":{"additional_data":{"type":"string","description":"Additional data."},"description":{"type":"string","description":"Description."},"entity_id":{"type":"integer","description":"Shipment item ID."},"name":{"type":"string","description":"Name."},"parent_id":{"type":"integer","description":"Parent ID."},"price":{"type":"number","description":"Price."},"product_id":{"type":"integer","description":"Product ID."},"row_total":{"type":"number","description":"Row total."},"sku":{"type":"string","description":"SKU."},"weight":{"type":"number","description":"Weight."},"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-item-extension-interface"},"order_item_id":{"type":"integer","description":"Order item ID."},"qty":{"type":"number","description":"Quantity."}},"required":["order_item_id","qty"]},"sales-data-shipment-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentItemInterface"},"sales-data-shipment-track-interface":{"type":"object","description":"Shipment track interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package. Merchants and customers can track shipments.","properties":{"order_id":{"type":"integer","description":"The order_id for the shipment package."},"created_at":{"type":"string","description":"Created-at timestamp."},"entity_id":{"type":"integer","description":"Shipment package ID."},"parent_id":{"type":"integer","description":"Parent ID."},"updated_at":{"type":"string","description":"Updated-at timestamp."},"weight":{"type":"number","description":"Weight."},"qty":{"type":"number","description":"Quantity."},"description":{"type":"string","description":"Description."},"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-track-extension-interface"},"track_number":{"type":"string","description":"Track number."},"title":{"type":"string","description":"Title."},"carrier_code":{"type":"string","description":"Carrier code."}},"required":["order_id","parent_id","weight","qty","description","track_number","title","carrier_code"]},"sales-data-shipment-track-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentTrackInterface"},"sales-data-shipment-comment-interface":{"type":"object","description":"Shipment comment interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package. A shipment document can contain comments.","properties":{"is_customer_notified":{"type":"integer","description":"Is-customer-notified flag value."},"parent_id":{"type":"integer","description":"Parent ID."},"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-comment-extension-interface"},"comment":{"type":"string","description":"Comment."},"is_visible_on_front":{"type":"integer","description":"Is-visible-on-storefront flag value."},"created_at":{"type":"string","description":"Created-at timestamp."},"entity_id":{"type":"integer","description":"Invoice ID."}},"required":["is_customer_notified","parent_id","comment","is_visible_on_front"]},"sales-data-shipment-comment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentCommentInterface"},"sales-data-shipment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentInterface"},"sales-data-shipment-search-result-interface":{"type":"object","description":"Shipment search result interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-shipment-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-shipment-comment-search-result-interface":{"type":"object","description":"Shipment comment search result interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package. A shipment document can contain comments.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-shipment-comment-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-shipment-item-creation-interface":{"type":"object","description":"Input argument for shipment item creation Interface ShipmentItemCreationInterface","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-item-creation-extension-interface"},"order_item_id":{"type":"integer","description":"Order item ID."},"qty":{"type":"number","description":"Quantity."}},"required":["order_item_id","qty"]},"sales-data-shipment-item-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentItemCreationInterface"},"sales-data-shipment-comment-creation-interface":{"type":"object","description":"Interface ShipmentCommentCreationInterface","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-comment-creation-extension-interface"},"comment":{"type":"string","description":"Comment."},"is_visible_on_front":{"type":"integer","description":"Is-visible-on-storefront flag value."}},"required":["comment","is_visible_on_front"]},"sales-data-shipment-comment-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentCommentCreationInterface"},"sales-data-shipment-track-creation-interface":{"type":"object","description":"Shipment Track Creation interface.","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-track-creation-extension-interface"},"track_number":{"type":"string","description":"Track number."},"title":{"type":"string","description":"Title."},"carrier_code":{"type":"string","description":"Carrier code."}},"required":["track_number","title","carrier_code"]},"sales-data-shipment-track-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentTrackCreationInterface"},"sales-data-shipment-package-creation-interface":{"type":"object","description":"Shipment package interface. A shipment is a delivery package that contains products. A shipment document accompanies the shipment. This document lists the products and their quantities in the delivery package.","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-package-creation-extension-interface"}}},"sales-data-shipment-package-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentPackageCreationInterface"},"sales-data-shipment-creation-arguments-interface":{"type":"object","description":"Interface for creation arguments for Shipment.","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-shipment-creation-arguments-extension-interface"}}},"sales-data-shipment-creation-arguments-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\ShipmentCreationArgumentsInterface"},"sales-data-transaction-interface":{"type":"object","description":"Transaction interface. A transaction is an interaction between a merchant and a customer such as a purchase, a credit, a refund, and so on.","properties":{"transaction_id":{"type":"integer","description":"Transaction ID."},"parent_id":{"type":"integer","description":"The parent ID for the transaction. Otherwise, null."},"order_id":{"type":"integer","description":"Order ID."},"payment_id":{"type":"integer","description":"Payment ID."},"txn_id":{"type":"string","description":"Transaction business ID."},"parent_txn_id":{"type":"string","description":"Parent transaction business ID."},"txn_type":{"type":"string","description":"Transaction type."},"is_closed":{"type":"integer","description":"Is-closed flag value."},"additional_information":{"type":"array","description":"Array of additional information. Otherwise, null.","items":{"type":"string"}},"created_at":{"type":"string","description":"Created-at timestamp."},"child_transactions":{"type":"array","description":"Array of child transactions.","items":{"$ref":"#/definitions/sales-data-transaction-interface"}},"extension_attributes":{"$ref":"#/definitions/sales-data-transaction-extension-interface"}},"required":["transaction_id","order_id","payment_id","txn_id","parent_txn_id","txn_type","is_closed","created_at","child_transactions"]},"sales-data-transaction-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\TransactionInterface"},"sales-data-transaction-search-result-interface":{"type":"object","description":"Transaction search result interface. A transaction is an interaction between a merchant and a customer such as a purchase, a credit, a refund, and so on.","properties":{"items":{"type":"array","description":"Array of collection items.","items":{"$ref":"#/definitions/sales-data-transaction-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-data-invoice-item-creation-interface":{"type":"object","description":"Input argument for invoice creation Interface InvoiceItemCreationInterface","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-invoice-item-creation-extension-interface"},"order_item_id":{"type":"integer","description":"Order item ID."},"qty":{"type":"number","description":"Quantity."}},"required":["order_item_id","qty"]},"sales-data-invoice-item-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\InvoiceItemCreationInterface"},"sales-data-invoice-comment-creation-interface":{"type":"object","description":"Interface InvoiceCommentCreationInterface","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-invoice-comment-creation-extension-interface"},"comment":{"type":"string","description":"Comment."},"is_visible_on_front":{"type":"integer","description":"Is-visible-on-storefront flag value."}},"required":["comment","is_visible_on_front"]},"sales-data-invoice-comment-creation-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\InvoiceCommentCreationInterface"},"sales-data-invoice-creation-arguments-interface":{"type":"object","description":"Interface for creation arguments for Invoice.","properties":{"extension_attributes":{"$ref":"#/definitions/sales-data-invoice-creation-arguments-extension-interface"}}},"sales-data-invoice-creation-arguments-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Sales\\Api\\Data\\InvoiceCreationArgumentsInterface"},"checkout-data-shipping-information-interface":{"type":"object","description":"Interface ShippingInformationInterface","properties":{"shipping_address":{"$ref":"#/definitions/quote-data-address-interface"},"billing_address":{"$ref":"#/definitions/quote-data-address-interface"},"shipping_method_code":{"type":"string","description":"Shipping method code"},"shipping_carrier_code":{"type":"string","description":"Carrier code"},"extension_attributes":{"$ref":"#/definitions/checkout-data-shipping-information-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["shipping_address","shipping_method_code","shipping_carrier_code"]},"checkout-data-shipping-information-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Checkout\\Api\\Data\\ShippingInformationInterface"},"checkout-data-payment-details-interface":{"type":"object","description":"Interface PaymentDetailsInterface","properties":{"payment_methods":{"type":"array","items":{"$ref":"#/definitions/quote-data-payment-method-interface"}},"totals":{"$ref":"#/definitions/quote-data-totals-interface"},"extension_attributes":{"$ref":"#/definitions/checkout-data-payment-details-extension-interface"}},"required":["payment_methods","totals"]},"checkout-data-payment-details-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Checkout\\Api\\Data\\PaymentDetailsInterface"},"checkout-data-totals-information-interface":{"type":"object","description":"Interface TotalsInformationInterface","properties":{"address":{"$ref":"#/definitions/quote-data-address-interface"},"shipping_method_code":{"type":"string","description":"Shipping method code"},"shipping_carrier_code":{"type":"string","description":"Carrier code"},"extension_attributes":{"$ref":"#/definitions/checkout-data-totals-information-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["address"]},"checkout-data-totals-information-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Checkout\\Api\\Data\\TotalsInformationInterface"},"checkout-agreements-data-agreement-interface":{"type":"object","description":"Interface AgreementInterface","properties":{"agreement_id":{"type":"integer","description":"Agreement ID."},"name":{"type":"string","description":"Agreement name."},"content":{"type":"string","description":"Agreement content."},"content_height":{"type":"string","description":"Agreement content height. Otherwise, null."},"checkbox_text":{"type":"string","description":"Agreement checkbox text."},"is_active":{"type":"boolean","description":"Agreement status."},"is_html":{"type":"boolean","description":"* true - HTML. * false - plain text."},"mode":{"type":"integer","description":"The agreement applied mode."},"extension_attributes":{"$ref":"#/definitions/checkout-agreements-data-agreement-extension-interface"}},"required":["agreement_id","name","content","checkbox_text","is_active","is_html","mode"]},"checkout-agreements-data-agreement-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\CheckoutAgreements\\Api\\Data\\AgreementInterface"},"gift-card-account-data-gift-card-account-interface":{"type":"object","description":"Gift Card Account data","properties":{"gift_cards":{"type":"array","description":"Cards codes","items":{"type":"string"}},"gift_cards_amount":{"type":"number","description":"Cards amount in quote currency"},"base_gift_cards_amount":{"type":"number","description":"Cards amount in base currency"},"gift_cards_amount_used":{"type":"number","description":"Cards amount used in quote currency"},"base_gift_cards_amount_used":{"type":"number","description":"Cards amount used in base currency"},"extension_attributes":{"$ref":"#/definitions/gift-card-account-data-gift-card-account-extension-interface"}},"required":["gift_cards","gift_cards_amount","base_gift_cards_amount","gift_cards_amount_used","base_gift_cards_amount_used"]},"gift-card-account-data-gift-card-account-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\GiftCardAccount\\Api\\Data\\GiftCardAccountInterface"},"tax-data-tax-rate-interface":{"type":"object","description":"Tax rate interface.","properties":{"id":{"type":"integer","description":"Id"},"tax_country_id":{"type":"string","description":"Country id"},"tax_region_id":{"type":"integer","description":"Region id"},"region_name":{"type":"string","description":"Region name"},"tax_postcode":{"type":"string","description":"Postcode"},"zip_is_range":{"type":"integer","description":"Zip is range"},"zip_from":{"type":"integer","description":"Zip range from"},"zip_to":{"type":"integer","description":"Zip range to"},"rate":{"type":"number","description":"Tax rate in percentage"},"code":{"type":"string","description":"Tax rate code"},"titles":{"type":"array","description":"Tax rate titles","items":{"$ref":"#/definitions/tax-data-tax-rate-title-interface"}},"extension_attributes":{"$ref":"#/definitions/tax-data-tax-rate-extension-interface"}},"required":["tax_country_id","rate","code"]},"tax-data-tax-rate-title-interface":{"type":"object","description":"Tax rate title interface.","properties":{"store_id":{"type":"string","description":"Store id"},"value":{"type":"string","description":"Title value"},"extension_attributes":{"$ref":"#/definitions/tax-data-tax-rate-title-extension-interface"}},"required":["store_id","value"]},"tax-data-tax-rate-title-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Tax\\Api\\Data\\TaxRateTitleInterface"},"tax-data-tax-rate-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Tax\\Api\\Data\\TaxRateInterface"},"tax-data-tax-rate-search-results-interface":{"type":"object","description":"Interface for tax rate search results.","properties":{"items":{"type":"array","description":"Items","items":{"$ref":"#/definitions/tax-data-tax-rate-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"tax-data-tax-rule-interface":{"type":"object","description":"Tax rule interface.","properties":{"id":{"type":"integer","description":"Id"},"code":{"type":"string","description":"Tax rule code"},"priority":{"type":"integer","description":"Priority"},"position":{"type":"integer","description":"Sort order."},"customer_tax_class_ids":{"type":"array","description":"Customer tax class id","items":{"type":"integer"}},"product_tax_class_ids":{"type":"array","description":"Product tax class id","items":{"type":"integer"}},"tax_rate_ids":{"type":"array","description":"Tax rate ids","items":{"type":"integer"}},"calculate_subtotal":{"type":"boolean","description":"Calculate subtotal."},"extension_attributes":{"$ref":"#/definitions/tax-data-tax-rule-extension-interface"}},"required":["code","priority","position","customer_tax_class_ids","product_tax_class_ids","tax_rate_ids"]},"tax-data-tax-rule-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Tax\\Api\\Data\\TaxRuleInterface"},"tax-data-tax-rule-search-results-interface":{"type":"object","description":"Interface for tax rule search results.","properties":{"items":{"type":"array","description":"Items","items":{"$ref":"#/definitions/tax-data-tax-rule-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"tax-data-tax-class-interface":{"type":"object","description":"Tax class interface.","properties":{"class_id":{"type":"integer","description":"Tax class ID."},"class_name":{"type":"string","description":"Tax class name."},"class_type":{"type":"string","description":"Tax class type."},"extension_attributes":{"$ref":"#/definitions/tax-data-tax-class-extension-interface"}},"required":["class_name","class_type"]},"tax-data-tax-class-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Tax\\Api\\Data\\TaxClassInterface"},"tax-data-tax-class-search-results-interface":{"type":"object","description":"Interface for tax class search results.","properties":{"items":{"type":"array","description":"Items","items":{"$ref":"#/definitions/tax-data-tax-class-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"gift-wrapping-data-wrapping-interface":{"type":"object","description":"Interface WrappingInterface","properties":{"wrapping_id":{"type":"integer"},"design":{"type":"string"},"status":{"type":"integer"},"base_price":{"type":"number"},"image_name":{"type":"string"},"image_base64_content":{"type":"string"},"base_currency_code":{"type":"string"},"website_ids":{"type":"array","items":{"type":"integer"}},"image_url":{"type":"string","description":"Wrapping image URL."},"extension_attributes":{"$ref":"#/definitions/gift-wrapping-data-wrapping-extension-interface"}},"required":["design","status","base_price"]},"gift-wrapping-data-wrapping-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\GiftWrapping\\Api\\Data\\WrappingInterface"},"gift-wrapping-data-wrapping-search-results-interface":{"type":"object","description":"Interface WrappingSearchResultsInterface","properties":{"items":{"type":"array","description":"Items","items":{"$ref":"#/definitions/gift-wrapping-data-wrapping-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-rule-data-rule-interface":{"type":"object","description":"Interface RuleInterface","properties":{"rule_id":{"type":"integer","description":"Rule id"},"name":{"type":"string","description":"Rule name"},"store_labels":{"type":"array","description":"Display label","items":{"$ref":"#/definitions/sales-rule-data-rule-label-interface"}},"description":{"type":"string","description":"Description"},"website_ids":{"type":"array","description":"A list of websites the rule applies to","items":{"type":"integer"}},"customer_group_ids":{"type":"array","description":"Ids of customer groups that the rule applies to","items":{"type":"integer"}},"from_date":{"type":"string","description":"The start date when the coupon is active"},"to_date":{"type":"string","description":"The end date when the coupon is active"},"uses_per_customer":{"type":"integer","description":"Number of uses per customer"},"is_active":{"type":"boolean","description":"The coupon is active"},"condition":{"$ref":"#/definitions/sales-rule-data-condition-interface"},"action_condition":{"$ref":"#/definitions/sales-rule-data-condition-interface"},"stop_rules_processing":{"type":"boolean","description":"To stop rule processing"},"is_advanced":{"type":"boolean","description":"Is this field needed"},"product_ids":{"type":"array","description":"Product ids","items":{"type":"integer"}},"sort_order":{"type":"integer","description":"Sort order"},"simple_action":{"type":"string","description":"Simple action of the rule"},"discount_amount":{"type":"number","description":"Discount amount"},"discount_qty":{"type":"number","description":"Maximum qty discount is applied"},"discount_step":{"type":"integer","description":"Discount step"},"apply_to_shipping":{"type":"boolean","description":"The rule applies to shipping"},"times_used":{"type":"integer","description":"How many times the rule has been used"},"is_rss":{"type":"boolean","description":"Whether the rule is in RSS"},"coupon_type":{"type":"string","description":"Coupon type"},"use_auto_generation":{"type":"boolean","description":"To auto generate coupon"},"uses_per_coupon":{"type":"integer","description":"Limit of uses per coupon"},"simple_free_shipping":{"type":"string","description":"To grant free shipping"},"extension_attributes":{"$ref":"#/definitions/sales-rule-data-rule-extension-interface"}},"required":["website_ids","customer_group_ids","uses_per_customer","is_active","stop_rules_processing","is_advanced","sort_order","discount_amount","discount_step","apply_to_shipping","times_used","is_rss","coupon_type","use_auto_generation","uses_per_coupon"]},"sales-rule-data-rule-label-interface":{"type":"object","description":"Interface RuleLabelInterface","properties":{"store_id":{"type":"integer","description":"StoreId"},"store_label":{"type":"string","description":"The label for the store"},"extension_attributes":{"$ref":"#/definitions/sales-rule-data-rule-label-extension-interface"}},"required":["store_id","store_label"]},"sales-rule-data-rule-label-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\SalesRule\\Api\\Data\\RuleLabelInterface"},"sales-rule-data-condition-interface":{"type":"object","description":"Interface ConditionInterface","properties":{"condition_type":{"type":"string","description":"Condition type"},"conditions":{"type":"array","description":"List of conditions","items":{"$ref":"#/definitions/sales-rule-data-condition-interface"}},"aggregator_type":{"type":"string","description":"The aggregator type"},"operator":{"type":"string","description":"The operator of the condition"},"attribute_name":{"type":"string","description":"The attribute name of the condition"},"value":{"type":"string","description":"The value of the condition"},"extension_attributes":{"$ref":"#/definitions/sales-rule-data-condition-extension-interface"}},"required":["condition_type","operator","value"]},"sales-rule-data-condition-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\SalesRule\\Api\\Data\\ConditionInterface"},"sales-rule-data-rule-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\SalesRule\\Api\\Data\\RuleInterface","properties":{"reward_points_delta":{"type":"integer"}}},"sales-rule-data-rule-search-result-interface":{"type":"object","description":"","properties":{"items":{"type":"array","description":"Rules.","items":{"$ref":"#/definitions/sales-rule-data-rule-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-rule-data-coupon-interface":{"type":"object","description":"Interface CouponInterface","properties":{"coupon_id":{"type":"integer","description":"Coupon id"},"rule_id":{"type":"integer","description":"The id of the rule associated with the coupon"},"code":{"type":"string","description":"Coupon code"},"usage_limit":{"type":"integer","description":"Usage limit"},"usage_per_customer":{"type":"integer","description":"Usage limit per customer"},"times_used":{"type":"integer","description":"The number of times the coupon has been used"},"expiration_date":{"type":"string","description":"Expiration date"},"is_primary":{"type":"boolean","description":"The coupon is primary coupon for the rule that it's associated with"},"created_at":{"type":"string","description":"When the coupon is created"},"type":{"type":"integer","description":"Of coupon"},"extension_attributes":{"$ref":"#/definitions/sales-rule-data-coupon-extension-interface"}},"required":["rule_id","times_used","is_primary"]},"sales-rule-data-coupon-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\SalesRule\\Api\\Data\\CouponInterface"},"sales-rule-data-coupon-search-result-interface":{"type":"object","description":"","properties":{"items":{"type":"array","description":"Rules.","items":{"$ref":"#/definitions/sales-rule-data-coupon-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"sales-rule-data-coupon-generation-spec-interface":{"type":"object","description":"CouponGenerationSpecInterface","properties":{"rule_id":{"type":"integer","description":"The id of the rule associated with the coupon"},"format":{"type":"string","description":"Format of generated coupon code"},"quantity":{"type":"integer","description":"Of coupons to generate"},"length":{"type":"integer","description":"Length of coupon code"},"prefix":{"type":"string","description":"The prefix"},"suffix":{"type":"string","description":"The suffix"},"delimiter_at_every":{"type":"integer","description":"The spacing where the delimiter should exist"},"delimiter":{"type":"string","description":"The delimiter"},"extension_attributes":{"$ref":"#/definitions/sales-rule-data-coupon-generation-spec-extension-interface"}},"required":["rule_id","format","quantity","length"]},"sales-rule-data-coupon-generation-spec-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\SalesRule\\Api\\Data\\CouponGenerationSpecInterface"},"sales-rule-data-coupon-mass-delete-result-interface":{"type":"object","description":"Coupon mass delete results interface.","properties":{"failed_items":{"type":"array","description":"List of failed items.","items":{"type":"string"}},"missing_items":{"type":"array","description":"List of missing items.","items":{"type":"string"}}},"required":["failed_items","missing_items"]},"rma-data-track-interface":{"type":"object","description":"Interface TrackInterface","properties":{"entity_id":{"type":"integer","description":"Entity id"},"rma_entity_id":{"type":"integer","description":"Rma entity id"},"track_number":{"type":"string","description":"Track number"},"carrier_title":{"type":"string","description":"Carrier title"},"carrier_code":{"type":"string","description":"Carrier code"},"extension_attributes":{"$ref":"#/definitions/rma-data-track-extension-interface"}},"required":["entity_id","rma_entity_id","track_number","carrier_title","carrier_code"]},"rma-data-track-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Rma\\Api\\Data\\TrackInterface"},"rma-data-track-search-result-interface":{"type":"object","description":"Interface TrackSearchResultInterface","properties":{"items":{"type":"array","description":"Rma list","items":{"$ref":"#/definitions/rma-data-track-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"rma-data-rma-interface":{"type":"object","description":"Interface RmaInterface","properties":{"increment_id":{"type":"string","description":"Entity_id"},"entity_id":{"type":"integer","description":"Entity_id"},"order_id":{"type":"integer","description":"Order_id"},"order_increment_id":{"type":"string","description":"Order_increment_id"},"store_id":{"type":"integer","description":"Store_id"},"customer_id":{"type":"integer","description":"Customer_id"},"date_requested":{"type":"string","description":"Date_requested"},"customer_custom_email":{"type":"string","description":"Customer_custom_email"},"items":{"type":"array","description":"Items","items":{"$ref":"#/definitions/rma-data-item-interface"}},"status":{"type":"string","description":"Status"},"comments":{"type":"array","description":"Comments list","items":{"$ref":"#/definitions/rma-data-comment-interface"}},"tracks":{"type":"array","description":"Tracks list","items":{"$ref":"#/definitions/rma-data-track-interface"}},"extension_attributes":{"$ref":"#/definitions/rma-data-rma-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["increment_id","entity_id","order_id","order_increment_id","store_id","customer_id","date_requested","customer_custom_email","items","status","comments","tracks"]},"rma-data-item-interface":{"type":"object","description":"Interface CategoryInterface","properties":{"entity_id":{"type":"integer","description":"Id"},"rma_entity_id":{"type":"integer","description":"RMA id"},"order_item_id":{"type":"integer","description":"Order_item_id"},"qty_requested":{"type":"integer","description":"Qty_requested"},"qty_authorized":{"type":"integer","description":"Qty_authorized"},"qty_approved":{"type":"integer","description":"Qty_approved"},"qty_returned":{"type":"integer","description":"Qty_returned"},"reason":{"type":"string","description":"Reason"},"condition":{"type":"string","description":"Condition"},"resolution":{"type":"string","description":"Resolution"},"status":{"type":"string","description":"Status"},"extension_attributes":{"$ref":"#/definitions/rma-data-item-extension-interface"}},"required":["entity_id","rma_entity_id","order_item_id","qty_requested","qty_authorized","qty_approved","qty_returned","reason","condition","resolution","status"]},"rma-data-item-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Rma\\Api\\Data\\ItemInterface"},"rma-data-comment-interface":{"type":"object","description":"Interface CommentInterface","properties":{"comment":{"type":"string","description":"Comment"},"rma_entity_id":{"type":"integer","description":"Rma Id"},"created_at":{"type":"string","description":"Created_at"},"entity_id":{"type":"integer","description":"Entity_id"},"customer_notified":{"type":"boolean","description":"Is_customer_notified"},"visible_on_front":{"type":"boolean","description":"Is_visible_on_front"},"status":{"type":"string","description":"Status"},"admin":{"type":"boolean","description":"Is_admin"},"extension_attributes":{"$ref":"#/definitions/rma-data-comment-extension-interface"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["comment","rma_entity_id","created_at","entity_id","customer_notified","visible_on_front","status","admin"]},"rma-data-comment-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Rma\\Api\\Data\\CommentInterface"},"rma-data-rma-extension-interface":{"type":"object","description":"ExtensionInterface class for @see \\Magento\\Rma\\Api\\Data\\RmaInterface"},"rma-data-comment-search-result-interface":{"type":"object","description":"Interface CommentSearchResultInterface","properties":{"items":{"type":"array","description":"Rma Status History list","items":{"$ref":"#/definitions/rma-data-comment-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"rma-data-rma-search-result-interface":{"type":"object","description":"Interface RmaSearchResultInterface","properties":{"items":{"type":"array","description":"Rma list","items":{"$ref":"#/definitions/rma-data-rma-interface"}},"search_criteria":{"$ref":"#/definitions/framework-search-criteria-interface"},"total_count":{"type":"integer","description":"Total count."}},"required":["items","search_criteria","total_count"]},"framework-metadata-object-interface":{"type":"object","description":"Provides metadata about an attribute.","properties":{"attribute_code":{"type":"string","description":"Code of the attribute."}},"required":["attribute_code"]},"test-module1-v1-entity-item":{"type":"object","description":"","properties":{"item_id":{"type":"integer"},"name":{"type":"string"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["item_id","name"]},"test-module1-v2-entity-item":{"type":"object","description":"","properties":{"id":{"type":"integer"},"name":{"type":"string"},"price":{"type":"string"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["id","name","price"]},"test-module2-v1-entity-item":{"type":"object","description":"","properties":{"id":{"type":"integer"},"name":{"type":"string"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["id","name"]},"test-module3-v1-entity-parameter":{"type":"object","description":"","properties":{"name":{"type":"string","description":"$name"},"value":{"type":"string","description":"$value"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["name","value"]},"test-module3-v1-entity-wrapped-error-parameter":{"type":"object","description":"","properties":{"field_name":{"type":"string","description":"$name"},"value":{"type":"string","description":"$value"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["field_name","value"]},"test-module4-v1-entity-data-object-response":{"type":"object","description":"","properties":{"entity_id":{"type":"integer"},"name":{"type":"string"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["entity_id","name"]},"test-module4-v1-entity-data-object-request":{"type":"object","description":"","properties":{"name":{"type":"string"},"entity_id":{"type":"integer"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["name"]},"test-module4-v1-entity-nested-data-object-request":{"type":"object","description":"","properties":{"details":{"$ref":"#/definitions/test-module4-v1-entity-data-object-request"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["details"]},"test-module4-v1-entity-extensible-request-interface":{"type":"object","description":"","properties":{"name":{"type":"string"},"entity_id":{"type":"integer"}},"required":["name"]},"test-module5-v1-entity-all-soap-and-rest":{"type":"object","description":"Some Data Object short description. Data Object long multi line description.","properties":{"entity_id":{"type":"integer","description":"Item ID"},"name":{"type":"string","description":"Item name"},"enabled":{"type":"boolean","description":"If entity is enabled"},"orders":{"type":"boolean","description":"If current entity has a property defined"},"custom_attributes":{"type":"array","description":"Custom attributes values.","items":{"$ref":"#/definitions/framework-attribute-interface"}}},"required":["entity_id","enabled","orders"]},"test-module5-v2-entity-all-soap-and-rest":{"type":"object","description":"Some Data Object short description. Data Object long multi line description.","properties":{"price":{"type":"integer"}},"required":["price"]},"test-module-ms-cdata-item-interface":{"type":"object","description":"","properties":{"item_id":{"type":"integer"},"name":{"type":"string"}},"required":["item_id","name"]}}} \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/definition.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/definition.mustache new file mode 100644 index 000000000..e61212219 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/definition.mustache @@ -0,0 +1,14 @@ + + + + + + {{> field2 }} + {{> array1 }} + + \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/operation.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/operation.mustache new file mode 100644 index 000000000..5114f233a --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/operation.mustache @@ -0,0 +1,16 @@ + + + + + + application/json + {{> field }} + {{> param }} + {{> array }} + + \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array1.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array1.mustache new file mode 100644 index 000000000..3669c78d0 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array1.mustache @@ -0,0 +1,12 @@ +{{! +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +}} +{{# arrays1 }} + + {{> value }} + {{> arrays2 }} + +{{/ arrays1 }} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array2.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array2.mustache new file mode 100644 index 000000000..072b430fb --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array2.mustache @@ -0,0 +1,12 @@ +{{! +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +}} +{{# arrays2 }} + + {{> value }} + {{> arrays3 }} + +{{/ arrays2 }} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array3.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array3.mustache new file mode 100644 index 000000000..401dbbcbd --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/array3.mustache @@ -0,0 +1,12 @@ +{{! +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +}} +{{! No array is nested more than 2 level in Magento2 swagger spec. }} +{{# arrays3 }} + + {{> value }} + +{{/ arrays3 }} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field.mustache new file mode 100644 index 000000000..29a822d05 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field.mustache @@ -0,0 +1,9 @@ +{{! +/** + * Copyright ? Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +}} +{{# fields }} +{{ fieldType }} +{{/ fields }} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field2.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field2.mustache new file mode 100644 index 000000000..bf4f6c2a5 --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/field2.mustache @@ -0,0 +1,9 @@ +{{! +/** + * Copyright ? Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +}} +{{# fields }} +{{ fieldType }} +{{/ fields }} diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/param.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/param.mustache new file mode 100644 index 000000000..be5f4a3ef --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/param.mustache @@ -0,0 +1,9 @@ +{{! +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +}} +{{# params }} +{{ paramType }} +{{/ params }} \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/value.mustache b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/value.mustache new file mode 100644 index 000000000..def0c03ff --- /dev/null +++ b/src/Magento/FunctionalTestingFramework/Util/MetadataGenerator/Swagger/views/partials/value.mustache @@ -0,0 +1,9 @@ +{{! +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +}} +{{# values }} +{{ value }} +{{/ values }} From 3b6581bdc08f392f3b815a336e5b2f88a9df8f2a Mon Sep 17 00:00:00 2001 From: Ian Meron Date: Wed, 8 Nov 2017 16:05:47 -0600 Subject: [PATCH 13/29] MQE-531: Unit and Verification tests do not run with MFTF PR - edit travis.yml file to include reference to all-checks command --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4aeda749c..2331317e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,4 +4,4 @@ php: - 7.1 install: composer install --no-interaction --prefer-source script: - - vendor/bin/phpcs ./src --standard=./dev/tests/static/Magento + - bin/all-checks From 4ea5fe2bbe67d31efe4156d32e3d103d986798ce Mon Sep 17 00:00:00 2001 From: Ian Meron Date: Thu, 9 Nov 2017 08:53:19 -0600 Subject: [PATCH 14/29] MQE-531: Unit and Verification tests do not run with MFTF PR - run checks in parallel --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2331317e4..78b1732ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,9 @@ php: - 7.0 - 7.1 install: composer install --no-interaction --prefer-source +matrix: + - VERIFICATION_TOOL=copyright-check + - VERIFICATION_TOOL=phpunit-checks + - VERIFICATION_TOOL=static-checks script: - - bin/all-checks + - bin/$VERIFICATION_TOOL From 6a17e5e47c059f3eecacf92de7c200f241ccbfc2 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk Date: Thu, 9 Nov 2017 17:09:57 +0200 Subject: [PATCH 15/29] MQE-531: Unit and Verification tests do not run with MFTF PR --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 78b1732ff..58b7b9b0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,8 @@ php: - 7.0 - 7.1 install: composer install --no-interaction --prefer-source -matrix: +env: + matrix: - VERIFICATION_TOOL=copyright-check - VERIFICATION_TOOL=phpunit-checks - VERIFICATION_TOOL=static-checks From f3848f1ba84c516e0c0e3b15defac8d7781bc622 Mon Sep 17 00:00:00 2001 From: Tom Reece Date: Mon, 13 Nov 2017 09:51:10 -0600 Subject: [PATCH 16/29] MQE-421: Create Unit Tests for the object model - Fixed CR feedback - Merged in sprint-develop and fixed conflicts --- .../Page/Objects/ElementObjectTest.php | 17 ++++++++++++++--- .../Page/Objects/SectionObjectTest.php | 12 ++++++------ .../Test/Objects/ActionObjectTest.php | 4 ++-- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php index aefef682e..747a1325e 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php @@ -6,6 +6,7 @@ namespace tests\unit\Magento\FunctionalTestFramework\Page\Objects; +use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\Page\Objects\ElementObject; use PHPUnit\Framework\TestCase; @@ -19,7 +20,7 @@ class ElementObjectTest extends TestCase */ public function testTimeoutDefault() { - $element = new ElementObject('name', 'type', 'selector', '-', false); + $element = new ElementObject('name', 'type', 'selector', null, '-', false); $this->assertNull($element->getTimeout()); } @@ -28,7 +29,7 @@ public function testTimeoutDefault() */ public function testTimeoutNotNull() { - $element = new ElementObject('name', 'type', 'selector', '15', false); + $element = new ElementObject('name', 'type', 'selector', null, '15', false); $timeout = $element->getTimeout(); $this->assertEquals(15, $timeout); $this->assertInternalType('int', $timeout); @@ -39,9 +40,19 @@ public function testTimeoutNotNull() */ public function testTimeoutCastFromString() { - $element = new ElementObject('name', 'type', 'selector', 'helloString', true); + $element = new ElementObject('name', 'type', 'selector', null, 'helloString', true); $timeout = $element->getTimeout(); $this->assertEquals(0, $timeout); $this->assertInternalType('int', $timeout); } + + + /** + * An exception should be thrown if both a selector and locatorFunction are passed + */ + public function testBothSelectorAndLocatorFunction() + { + $this->expectException(XmlException::class); + new ElementObject('name', 'type', 'selector', 'cantDoThis', 'helloString', true); + } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php index 0caab118b..199d2a225 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php @@ -19,8 +19,8 @@ class SectionObjectTest extends TestCase * Assert that the section object has an element */ public function testHasElement() { - $element1 = new ElementObject('element1', 'type', '#selector', '41', false); - $element2 = new ElementObject('element2', 'type', '#selector', '42', true); + $element1 = new ElementObject('element1', 'type', '#selector', null, '41', false); + $element2 = new ElementObject('element2', 'type', '#selector', null, '42', true); $elements = [ 'element1' => $element1, 'element2' => $element2 @@ -33,7 +33,7 @@ public function testHasElement() { * Assert that the section object doesn't have an element */ public function testDoesntHaveElement() { - $element2 = new ElementObject('element2', 'type', '#selector', '42', true); + $element2 = new ElementObject('element2', 'type', '#selector', null, '42', true); $elements = [ 'element2' => $element2 ]; @@ -45,8 +45,8 @@ public function testDoesntHaveElement() { * Assert that an element object is returned */ public function testGetElement() { - $element1 = new ElementObject('element1', 'type', '#selector', '41', false); - $element2 = new ElementObject('element2', 'type', '#selector', '42', true); + $element1 = new ElementObject('element1', 'type', '#selector', null, '41', false); + $element2 = new ElementObject('element2', 'type', '#selector', null, '42', true); $elements = [ 'element1' => $element1, 'element2' => $element2 @@ -61,7 +61,7 @@ public function testGetElement() { * Assert that null is returned if no such element */ public function testNullGetElement() { - $element1 = new ElementObject('element1', 'type', '#selector', '41', false); + $element1 = new ElementObject('element1', 'type', '#selector', null, '41', false); $elements = [ 'element1' => $element1 ]; diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php index 1037eb394..5ab71810c 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Objects/ActionObjectTest.php @@ -50,7 +50,7 @@ public function testResolveElementInSelector() 'selector' => '{{SectionObject.elementObject}}', 'userInput' => 'Hello world' ]); - $elementObject = new ElementObject('elementObject', 'button', '#replacementSelector', '42', false); + $elementObject = new ElementObject('elementObject', 'button', '#replacementSelector', null, '42', false); $sectionObject = new SectionObject('SectionObject', ['elementObject' => $elementObject]); $instance = AspectMock::double(SectionObjectHandler::class, ['getObject' => $sectionObject]) ->make(); // bypass the private constructor @@ -92,7 +92,7 @@ public function testTimeoutFromElement() $actionObject = new ActionObject('merge123', 'click', [ 'selector' => '{{SectionObject.elementObject}}' ]); - $elementObject = new ElementObject('elementObject', 'button', '#replacementSelector', '42', false); + $elementObject = new ElementObject('elementObject', 'button', '#replacementSelector', null, '42', false); $sectionObject = new SectionObject('SectionObject', ['elementObject' => $elementObject]); $instance = AspectMock::double(SectionObjectHandler::class, ['getObject' => $sectionObject]) ->make(); // bypass the private constructor From 33a862ff72d53ac769c3d095d005a8720c6923b2 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Mon, 13 Nov 2017 09:53:45 -0600 Subject: [PATCH 17/29] MQE-462: Update waitForLoadingMaskToDisappear to handle duplicated masks - Changed loadingMasks to an array - Changed waitForLoadingMaskToDisappear to recurse through all loading mask elements if multiple are found. --- .../Module/MagentoWebDriver.php | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php index f2004b1ee..b6e6e2800 100644 --- a/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php +++ b/src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php @@ -41,7 +41,13 @@ class MagentoWebDriver extends WebDriver { use AttachmentSupport; - public static $loadingMask = '.loading-mask'; + public static $loadingMasksLocators = [ + '//div[contains(@class, "loading-mask")]', + '//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"]' + ]; /** * The module required fields, to be set in the suite .yml configuration file. @@ -189,17 +195,20 @@ public function waitForPageLoad($timeout = 15) { $this->waitForJS('return document.readyState == "complete"', $timeout); $this->waitForAjaxLoad($timeout); - $this->waitForElementNotVisible('.loading-mask', 30); - $this->waitForElementNotVisible('.admin_data-grid-loading-mask', 30); - $this->waitForElementNotVisible('.admin__form-loading-mask', 30); + $this->waitForLoadingMaskToDisappear(); } /** - * Wait for the Loading mask to disappear. + * Wait for all visible loading masks to disappear. Gets all elements by mask selector, then loops over them. */ public function waitForLoadingMaskToDisappear() { - $this->waitForElementNotVisible(self::$loadingMask, 30); + foreach( self::$loadingMasksLocators as $maskLocator) { + $loadingMaskElements = $this->_findElements($maskLocator); + for ($i = 1; $i <= count($loadingMaskElements); $i++) { + $this->waitForElementNotVisible("{$maskLocator}[{$i}]", 30); + } + } } /** From a053dd008ad5b74c90a0a30eb195b3177bd6ad45 Mon Sep 17 00:00:00 2001 From: Tom Reece Date: Mon, 13 Nov 2017 12:04:32 -0600 Subject: [PATCH 18/29] MQE-421: Create Unit Tests for the object model - Add a test for both selector and locatorFunction null --- .../Page/Objects/ElementObjectTest.php | 12 ++++++++++-- .../Page/Objects/ElementObject.php | 3 ++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php index 747a1325e..00d5e9479 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/ElementObjectTest.php @@ -46,13 +46,21 @@ public function testTimeoutCastFromString() $this->assertInternalType('int', $timeout); } - /** * An exception should be thrown if both a selector and locatorFunction are passed */ public function testBothSelectorAndLocatorFunction() { $this->expectException(XmlException::class); - new ElementObject('name', 'type', 'selector', 'cantDoThis', 'helloString', true); + new ElementObject('name', 'type', 'selector', 'cantHaveThisAndSelector', '-', false); + } + + /** + * An exception should be thrown if neither a selector nor locatorFunction are passed + */ + public function testNeitherSelectorNorLocatorFunction() + { + $this->expectException(XmlException::class); + new ElementObject('name', 'type', null, null, '-', false); } } diff --git a/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php b/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php index f0bc1f404..f8738bc93 100644 --- a/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php +++ b/src/Magento/FunctionalTestingFramework/Page/Objects/ElementObject.php @@ -68,9 +68,10 @@ class ElementObject */ public function __construct($name, $type, $selector, $locatorFunction, $timeout, $parameterized) { - //Elements cannot have both a selector and a locatorFunction defined if ($selector != null && $locatorFunction != null) { throw new XmlException("Element '{$name}' cannot have both a selector and a locatorFunction."); + } elseif ($selector == null && $locatorFunction == null) { + throw new XmlException("Element '{$name}' must have either a selector or a locatorFunction.'"); } $this->name = $name; From 60a7244766a39c0a2ac7a05c93cd0b92db0041db Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Mon, 13 Nov 2017 12:07:09 -0600 Subject: [PATCH 19/29] MQE-544: Fixed verification test filenames. --- .../{testSuiteGeneration1.txt => TestSuiteGeneration1.txt} | 0 .../Cest/{basicFunctionalCest.xml => BasicFunctionalCest.xml} | 0 .../Cest/{dataReplacementCest.xml => DataReplacementCest.xml} | 0 .../Cest/{pageReplacementCest.xml => PageReplacementCest.xml} | 0 ...{persistedReplacementCest.xml => PersistedReplacementCest.xml} | 0 .../{sectionReplacementCest.xml => SectionReplacementCest.xml} | 0 .../TestModule/Data/{replacementData.xml => ReplacementData.xml} | 0 .../TestModule/Metadata/{placeholder.txt => Placeholder.txt} | 0 .../TestModule/Section/{zMergeSection.xml => ZMergeSection.xml} | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename dev/tests/verification/Resources/{testSuiteGeneration1.txt => TestSuiteGeneration1.txt} (100%) rename dev/tests/verification/TestModule/Cest/{basicFunctionalCest.xml => BasicFunctionalCest.xml} (100%) rename dev/tests/verification/TestModule/Cest/{dataReplacementCest.xml => DataReplacementCest.xml} (100%) rename dev/tests/verification/TestModule/Cest/{pageReplacementCest.xml => PageReplacementCest.xml} (100%) rename dev/tests/verification/TestModule/Cest/{persistedReplacementCest.xml => PersistedReplacementCest.xml} (100%) rename dev/tests/verification/TestModule/Cest/{sectionReplacementCest.xml => SectionReplacementCest.xml} (100%) rename dev/tests/verification/TestModule/Data/{replacementData.xml => ReplacementData.xml} (100%) rename dev/tests/verification/TestModule/Metadata/{placeholder.txt => Placeholder.txt} (100%) rename dev/tests/verification/TestModule/Section/{zMergeSection.xml => ZMergeSection.xml} (100%) diff --git a/dev/tests/verification/Resources/testSuiteGeneration1.txt b/dev/tests/verification/Resources/TestSuiteGeneration1.txt similarity index 100% rename from dev/tests/verification/Resources/testSuiteGeneration1.txt rename to dev/tests/verification/Resources/TestSuiteGeneration1.txt diff --git a/dev/tests/verification/TestModule/Cest/basicFunctionalCest.xml b/dev/tests/verification/TestModule/Cest/BasicFunctionalCest.xml similarity index 100% rename from dev/tests/verification/TestModule/Cest/basicFunctionalCest.xml rename to dev/tests/verification/TestModule/Cest/BasicFunctionalCest.xml diff --git a/dev/tests/verification/TestModule/Cest/dataReplacementCest.xml b/dev/tests/verification/TestModule/Cest/DataReplacementCest.xml similarity index 100% rename from dev/tests/verification/TestModule/Cest/dataReplacementCest.xml rename to dev/tests/verification/TestModule/Cest/DataReplacementCest.xml diff --git a/dev/tests/verification/TestModule/Cest/pageReplacementCest.xml b/dev/tests/verification/TestModule/Cest/PageReplacementCest.xml similarity index 100% rename from dev/tests/verification/TestModule/Cest/pageReplacementCest.xml rename to dev/tests/verification/TestModule/Cest/PageReplacementCest.xml diff --git a/dev/tests/verification/TestModule/Cest/persistedReplacementCest.xml b/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml similarity index 100% rename from dev/tests/verification/TestModule/Cest/persistedReplacementCest.xml rename to dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml diff --git a/dev/tests/verification/TestModule/Cest/sectionReplacementCest.xml b/dev/tests/verification/TestModule/Cest/SectionReplacementCest.xml similarity index 100% rename from dev/tests/verification/TestModule/Cest/sectionReplacementCest.xml rename to dev/tests/verification/TestModule/Cest/SectionReplacementCest.xml diff --git a/dev/tests/verification/TestModule/Data/replacementData.xml b/dev/tests/verification/TestModule/Data/ReplacementData.xml similarity index 100% rename from dev/tests/verification/TestModule/Data/replacementData.xml rename to dev/tests/verification/TestModule/Data/ReplacementData.xml diff --git a/dev/tests/verification/TestModule/Metadata/placeholder.txt b/dev/tests/verification/TestModule/Metadata/Placeholder.txt similarity index 100% rename from dev/tests/verification/TestModule/Metadata/placeholder.txt rename to dev/tests/verification/TestModule/Metadata/Placeholder.txt diff --git a/dev/tests/verification/TestModule/Section/zMergeSection.xml b/dev/tests/verification/TestModule/Section/ZMergeSection.xml similarity index 100% rename from dev/tests/verification/TestModule/Section/zMergeSection.xml rename to dev/tests/verification/TestModule/Section/ZMergeSection.xml From 730f0639036f69d79dfac88489d697ae2ab83b25 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Mon, 13 Nov 2017 15:53:45 -0600 Subject: [PATCH 20/29] MQE-516: Duplicated $data.key$ references are not replaced correctly - replacement now always appends "" . and . "" to replacement, then strips if unecessary. - edited expected output in verification tests. --- .../Resources/ActionGroupFunctionalCest.txt | 4 +-- .../Resources/ParameterArrayCest.txt | 2 +- .../Util/TestGenerator.php | 29 ++++--------------- 3 files changed, 8 insertions(+), 27 deletions(-) diff --git a/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt b/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt index 9a5344a7c..f5489905a 100644 --- a/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt +++ b/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt @@ -110,7 +110,7 @@ class ActionGroupFunctionalCest $I->amOnPage("/" . $createPerson->getCreatedDataByName('firstname') . "/" . $createPerson->getCreatedDataByName('lastname') . ".html"); $I->fillField("#foo", $createPerson->getCreatedDataByName('firstname')); $I->fillField("#bar", $createPerson->getCreatedDataByName('lastname')); - $I->searchAndMultiSelectOption("#foo", [$createPerson->getCreatedDataByName('firstname') . "", "" . $createPerson->getCreatedDataByName('lastname')]); + $I->searchAndMultiSelectOption("#foo", [$createPerson->getCreatedDataByName('firstname'), $createPerson->getCreatedDataByName('lastname')]); $I->see("#element ." . $createPerson->getCreatedDataByName('firstname')); } @@ -124,7 +124,7 @@ class ActionGroupFunctionalCest $I->amOnPage("/" . $this->createPersonParam->getCreatedDataByName('firstname') . "/" . $this->createPersonParam->getCreatedDataByName('lastname') . ".html"); $I->fillField("#foo", $this->createPersonParam->getCreatedDataByName('firstname')); $I->fillField("#bar", $this->createPersonParam->getCreatedDataByName('lastname')); - $I->searchAndMultiSelectOption("#foo", [$this->createPersonParam->getCreatedDataByName('firstname') . "", "" . $this->createPersonParam->getCreatedDataByName('lastname')]); + $I->searchAndMultiSelectOption("#foo", [$this->createPersonParam->getCreatedDataByName('firstname'), $this->createPersonParam->getCreatedDataByName('lastname')]); $I->see("#element ." . $this->createPersonParam->getCreatedDataByName('firstname')); } diff --git a/dev/tests/verification/Resources/ParameterArrayCest.txt b/dev/tests/verification/Resources/ParameterArrayCest.txt index 496e5670b..c07354af1 100644 --- a/dev/tests/verification/Resources/ParameterArrayCest.txt +++ b/dev/tests/verification/Resources/ParameterArrayCest.txt @@ -34,7 +34,7 @@ class ParameterArrayCest $I->searchAndMultiSelectOption("#selector", [msq("simpleParamData")."prename"]); $I->searchAndMultiSelectOption("#selector", ["postname".msq("simpleParamData")]); $I->searchAndMultiSelectOption("#selector", [$simpleDataKey->getCreatedDataByName('name')]); - $I->searchAndMultiSelectOption("#selector", ["name", "" . $simpleDataKey->getCreatedDataByName('name')]); + $I->searchAndMultiSelectOption("#selector", ["name", $simpleDataKey->getCreatedDataByName('name')]); $I->searchAndMultiSelectOption("#selector", ['someKey' => $simpleDataKey->getCreatedDataByName('name')]); $I->searchAndMultiSelectOption("#selector", ['someKey' => "name"]); $I->searchAndMultiSelectOption("#selector", ['someKey' => msq("simpleParamData")."prename"]); diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index fde105f67..22d7c75c0 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1001,31 +1001,12 @@ private function replaceMatchesIntoArg($matches, &$outputArg, $delimiter) */ private function processQuoteBreaks($match, $argument, $replacement) { - $outputArg = $argument; - $beforeIndex = strpos($outputArg, $match) - 1; - $afterIndex = $beforeIndex + strlen($match) + 1; - - $quoteBefore = false; - // Determine if there is a " before/after the $match, and if there is only one " before/after match. - if ($beforeIndex == 0 - || ($argument[$beforeIndex] == '"' && substr_count($argument, '"', 0, $beforeIndex) < 1)) { - $quoteBefore = true; - } - $quoteAfter = $argument[$afterIndex] == '"' && substr_count($argument, '"', $afterIndex+1) < 1; + $outputArg = str_replace($match, '" . ' . $replacement . ' . "', $argument); - //Remove quotes at either end of argument if they aren't necessary. Add double-quote concatenation if needed. - if ($quoteBefore) { - $outputArg = substr($outputArg, 0, $beforeIndex) . substr($outputArg, $beforeIndex+1); - $afterIndex--; - } else { - $replacement = '" . ' . $replacement; - } - if ($quoteAfter) { - $outputArg = substr($outputArg, 0, $afterIndex) . substr($outputArg, $afterIndex+1); - } else { - $replacement = $replacement . ' . "'; - } - $outputArg = str_replace($match, $replacement, $outputArg); + //Sanitize string of any unnecessary '"" .' and '. ""'. + //Regex means: Search for '"" . ' but not '\"" . ' and ' . ""'. + //Matches on '"" . ' and ' . ""', but not on '\"" . ' and ' . "\"'. + $outputArg = preg_replace('/(?(? Date: Tue, 14 Nov 2017 09:27:49 -0600 Subject: [PATCH 21/29] MQE-516: Duplicated $data.key$ references are not replaced correctly - Verification Test Fixes --- dev/tests/verification/Resources/LocatorFunctionCest.txt | 8 ++++---- .../verification/Resources/PersistedReplacementCest.txt | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dev/tests/verification/Resources/LocatorFunctionCest.txt b/dev/tests/verification/Resources/LocatorFunctionCest.txt index 6ee99c63e..b716443c0 100644 --- a/dev/tests/verification/Resources/LocatorFunctionCest.txt +++ b/dev/tests/verification/Resources/LocatorFunctionCest.txt @@ -35,12 +35,12 @@ class LocatorFunctionCest $I->click(Locator::find("'img'", ['title' => 'diagram'])); $I->click(Locator::contains("string", "'Name'")); $I->click(Locator::contains("John", "'Name'")); - $I->click(Locator::contains($data->getCreatedDataByName('key') . "", "'Name'")); + $I->click(Locator::contains($data->getCreatedDataByName('key'), "'Name'")); $I->click(Locator::contains("string1", "string2")); $I->click(Locator::contains("John", "Doe")); - $I->click(Locator::contains($data->getCreatedDataByName('key1') . "", "" . $data->getCreatedDataByName('key2'))); + $I->click(Locator::contains($data->getCreatedDataByName('key1'), $data->getCreatedDataByName('key2'))); $I->click(Locator::contains("string1", "John")); - $I->click(Locator::contains("string1", "" . $data->getCreatedDataByName('key1'))); - $I->click(Locator::contains("John", "" . $data->getCreatedDataByName('key1'))); + $I->click(Locator::contains("string1", $data->getCreatedDataByName('key1'))); + $I->click(Locator::contains("John", $data->getCreatedDataByName('key1'))); } } diff --git a/dev/tests/verification/Resources/PersistedReplacementCest.txt b/dev/tests/verification/Resources/PersistedReplacementCest.txt index c0c0d0a7e..4ff8d853e 100644 --- a/dev/tests/verification/Resources/PersistedReplacementCest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementCest.txt @@ -48,8 +48,8 @@ class PersistedReplacementCest $I->dragAndDrop("#" . $createdData->getCreatedDataByName('firstname'), $createdData->getCreatedDataByName('lastname')); $I->conditionalClick($createdData->getCreatedDataByName('lastname'), "#" . $createdData->getCreatedDataByName('firstname'), true); $I->amOnUrl($createdData->getCreatedDataByName('firstname') . ".html"); - $I->searchAndMultiSelectOption("#selector", [$createdData->getCreatedDataByName('firstname') . "", "" . $createdData->getCreatedDataByName('lastname')]); + $I->searchAndMultiSelectOption("#selector", [$createdData->getCreatedDataByName('firstname'), $createdData->getCreatedDataByName('lastname')]); $I->fillField("#selector", "John " . $createdData->getCreatedDataByName('firstname') . " stringLiteral"); - $I->searchAndMultiSelectOption("#selector", [$createdData->getCreatedDataByName('firstname') . "", "John", "stringLiteral"]); + $I->searchAndMultiSelectOption("#selector", [$createdData->getCreatedDataByName('firstname'), "John", "stringLiteral"]); } } From cd4ac249f2e0e7076098cf201a439b947eabad6d Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Tue, 14 Nov 2017 14:02:44 -0600 Subject: [PATCH 22/29] MQE-544: Fixed verification test filenames and set assertFileEquals() to ignore cases. --- dev/tests/verification/Tests/SuiteGenerationTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index fc34b9af1..aabd45f01 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -56,8 +56,8 @@ public function testSuiteGeneration1() $groupName . DIRECTORY_SEPARATOR . TestManifest::TEST_MANIFEST_FILENAME; - $expectedManifest = self::RESOURCES_DIR . DIRECTORY_SEPARATOR . __FUNCTION__ . ".txt"; - $this->assertFileEquals($expectedManifest, $actualManifest); + $expectedManifest = self::RESOURCES_DIR . DIRECTORY_SEPARATOR . "TestSuiteGeneration1.txt"; + $this->assertFileEquals($expectedManifest, $actualManifest, '', true, true); } public static function tearDownAfterClass() From 2e966be425a68dca9fa447d5312ed254d4072bab Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Wed, 15 Nov 2017 13:33:48 -0600 Subject: [PATCH 23/29] MQE-497: Add useCaseId annotation - added useCaseId to Test Schema. - di.xml changes - Refarctored TestGenerator to use a single Annotation Generation mechanism. - Updated Verification Tests, turns out there was a bug in existing code. --- .../Resources/ActionGroupFunctionalCest.txt | 2 +- .../Resources/BasicFunctionalCest.txt | 4 +- .../Resources/MergeFunctionalCest.txt | 2 +- etc/di.xml | 2 + .../Test/etc/testSchema.xsd | 1 + .../Util/TestGenerator.php | 149 +++++------------- 6 files changed, 47 insertions(+), 113 deletions(-) diff --git a/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt b/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt index f5489905a..39a406e20 100644 --- a/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt +++ b/dev/tests/verification/Resources/ActionGroupFunctionalCest.txt @@ -17,7 +17,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Severity(level = SeverityLevel::CRITICAL) - * @Title("Title") + * @Title("A Functional Cest") * @group functional * @Features({"Action Group Functional Cest"}) * @Stories({"MQE-433"}) diff --git a/dev/tests/verification/Resources/BasicFunctionalCest.txt b/dev/tests/verification/Resources/BasicFunctionalCest.txt index c59bf9926..b7afc27d9 100644 --- a/dev/tests/verification/Resources/BasicFunctionalCest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalCest.txt @@ -17,7 +17,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Severity(level = SeverityLevel::CRITICAL) - * @Title("Title") + * @Title("A Functional Cest") * @group functional * @Features({"Basic Functional Cest"}) * @Stories({"MQE-305"}) @@ -37,10 +37,10 @@ class BasicFunctionalCest /** * @Severity(level = SeverityLevel::SEVERE) * @Title("Basic Functional Test") + * @group functionalTest * @Features({"Hardcoded Functional Test"}) * @Stories({"MQE-425"}) * @Parameter(name = "AcceptanceTester", value="$I") - * @group functionalTest * @param AcceptanceTester $I * @return void */ diff --git a/dev/tests/verification/Resources/MergeFunctionalCest.txt b/dev/tests/verification/Resources/MergeFunctionalCest.txt index aa6a75a43..36fc00b80 100644 --- a/dev/tests/verification/Resources/MergeFunctionalCest.txt +++ b/dev/tests/verification/Resources/MergeFunctionalCest.txt @@ -17,7 +17,7 @@ use Yandex\Allure\Adapter\Annotation\TestCaseId; /** * @Severity(level = SeverityLevel::CRITICAL) - * @Title("Title") + * @Title("A Functional Cest") * @group mergeTest * @Features({"Merge Functional Cest"}) * @Stories({"MQE-433"}) diff --git a/etc/di.xml b/etc/di.xml index 60071a55f..6da2220cb 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -242,6 +242,7 @@ /config/cest/annotations/description /config/cest/annotations/severity /config/cest/annotations/testCaseId + /config/cest/annotations/useCaseId /config/cest/annotations/group /config/cest/annotations/return /config/cest/test/annotations/features @@ -250,6 +251,7 @@ /config/cest/test/annotations/description /config/cest/test/annotations/severity /config/cest/test/annotations/testCaseId + /config/cest/test/annotations/useCaseId /config/cest/test/annotations/group /config/cest/test/annotations/env /config/cest/test/annotations/return diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd index fcd54a924..29e081779 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd @@ -55,6 +55,7 @@ + diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 22d7c75c0..73c82b0f6 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -18,6 +18,7 @@ class TestGenerator { const REQUIRED_ENTITY_REFERENCE = 'createDataKey'; + const TEST_SCOPE = 'Test'; const GENERATED_DIR = '_generated'; /** @@ -151,7 +152,7 @@ public function createAllCestFiles($runConfig = null) private function assembleCestPhp($cestObject) { $usePhp = $this->generateUseStatementsPhp(); - $classAnnotationsPhp = $this->generateClassAnnotationsPhp($cestObject->getAnnotations()); + $classAnnotationsPhp = $this->generateAnnotationsPhp($cestObject->getAnnotations(), "Cest"); $className = $cestObject->getName(); $className = str_replace(' ', '', $className); try { @@ -234,17 +235,22 @@ private function generateUseStatementsPhp() } /** - * Creates a PHP string for the Class Annotations block if the Cest file contains an block, outside - * of the blocks. - * - * @param array $classAnnotationsObject + * Generates Annotations PHP for given object, using given scope to determine indentation and additional output. + * @param array $annotationsObject + * @param string $scope * @return string */ - private function generateClassAnnotationsPhp($classAnnotationsObject) + private function generateAnnotationsPhp($annotationsObject, $scope) { - $classAnnotationsPhp = "/**\n"; + if ($scope == self::TEST_SCOPE) { + $indent = "\t"; + } else { + $indent = ""; + } - foreach ($classAnnotationsObject as $annotationType => $annotationName) { + $annotationsPhp = "{$indent}/**\n"; + + foreach ($annotationsObject as $annotationType => $annotationName) { if ($annotationType == "features") { $features = ""; @@ -256,7 +262,7 @@ private function generateClassAnnotationsPhp($classAnnotationsObject) } } - $classAnnotationsPhp .= sprintf(" * @Features({%s})\n", $features); + $annotationsPhp .= sprintf("{$indent} * @Features({%s})\n", $features); } if ($annotationType == "stories") { @@ -270,45 +276,55 @@ private function generateClassAnnotationsPhp($classAnnotationsObject) } } - $classAnnotationsPhp .= sprintf(" * @Stories({%s})\n", $stories); + $annotationsPhp .= sprintf("{$indent} * @Stories({%s})\n", $stories); } if ($annotationType == "title") { - $classAnnotationsPhp .= sprintf( - " * @Title(\"%s\")\n", - ucwords($annotationType), - $annotationName[0] - ); + $annotationsPhp .= sprintf("{$indent} * @Title(\"%s\")\n", $annotationName[0]); } if ($annotationType == "description") { - $classAnnotationsPhp .= sprintf(" * @Description(\"%s\")\n", $annotationName[0]); + $annotationsPhp .= sprintf("{$indent} * @Description(\"%s\")\n", $annotationName[0]); } if ($annotationType == "severity") { - $classAnnotationsPhp .= sprintf(" * @Severity(level = SeverityLevel::%s)\n", $annotationName[0]); + $annotationsPhp .= sprintf("{$indent} * @Severity(level = SeverityLevel::%s)\n", $annotationName[0]); } if ($annotationType == "testCaseId") { - $classAnnotationsPhp .= sprintf(" * TestCaseId(\"%s\")\n", $annotationName[0]); + $annotationsPhp .= sprintf("{$indent} * @TestCaseId(\"%s\")\n", $annotationName[0]); + } + + if ($annotationType == "useCaseId") { + $annotationsPhp .= sprintf("{$indent} * @UseCaseId(\"%s\")\n", $annotationName[0]); } if ($annotationType == "group") { foreach ($annotationName as $group) { - $classAnnotationsPhp .= sprintf(" * @group %s\n", $group); + $annotationsPhp .= sprintf("{$indent} * @group %s\n", $group); } } if ($annotationType == "env") { foreach ($annotationName as $env) { - $classAnnotationsPhp .= sprintf(" * @env %s\n", $env); + $annotationsPhp .= sprintf("{$indent} * @env %s\n", $env); } } } - $classAnnotationsPhp .= " */\n"; + if ($scope == self::TEST_SCOPE) { + $annotationsPhp .= sprintf( + "{$indent} * @Parameter(name = \"%s\", value=\"$%s\")\n", + "AcceptanceTester", + "I" + ); + $annotationsPhp .= sprintf("{$indent} * @param %s $%s\n", "AcceptanceTester", "I"); + $annotationsPhp .= "{$indent} * @return void\n"; + } + + $annotationsPhp .= "{$indent} */\n"; - return $classAnnotationsPhp; + return $annotationsPhp; } /** @@ -1119,97 +1135,12 @@ private function generateHooksPhp($hookObjects) return $hooks; } - /** - * Creates a PHP string for the Test Annotations block if the Test contains an block. - * - * @param array $testAnnotationsObject - * @return string - */ - private function generateTestAnnotationsPhp($testAnnotationsObject) - { - $testAnnotationsPhp = "\t/**\n"; - - foreach ($testAnnotationsObject as $annotationType => $annotationName) { - if ($annotationType == "features") { - $features = ""; - - foreach ($annotationName as $name) { - $features .= sprintf("\"%s\"", $name); - - if (next($annotationName)) { - $features .= ", "; - } - } - - $testAnnotationsPhp .= sprintf("\t * @Features({%s})\n", $features); - } - - if ($annotationType == "stories") { - $stories = ""; - - foreach ($annotationName as $name) { - $stories .= sprintf("\"%s\"", $name); - - if (next($annotationName)) { - $stories .= ", "; - } - } - - $testAnnotationsPhp .= sprintf("\t * @Stories({%s})\n", $stories); - } - - if ($annotationType == "title") { - $testAnnotationsPhp .= sprintf("\t * @Title(\"%s\")\n", $annotationName[0]); - } - - if ($annotationType == "description") { - $testAnnotationsPhp .= sprintf("\t * @Description(\"%s\")\n", $annotationName[0]); - } - - if ($annotationType == "severity") { - $testAnnotationsPhp .= sprintf( - "\t * @Severity(level = SeverityLevel::%s)\n", - $annotationName[0] - ); - } - - if ($annotationType == "testCaseId") { - $testAnnotationsPhp .= sprintf("\t * @TestCaseId(\"%s\")\n", $annotationName[0]); - } - } - - $testAnnotationsPhp .= sprintf( - "\t * @Parameter(name = \"%s\", value=\"$%s\")\n", - "AcceptanceTester", - "I" - ); - - foreach ($testAnnotationsObject as $annotationType => $annotationName) { - if ($annotationType == "group") { - foreach ($annotationName as $name) { - $testAnnotationsPhp .= sprintf("\t * @group %s\n", $name); - } - } - - if ($annotationType == "env") { - foreach ($annotationName as $env) { - $testAnnotationsPhp .= sprintf("\t * @env %s\n", $env); - } - } - } - - $testAnnotationsPhp .= sprintf("\t * @param %s $%s\n", "AcceptanceTester", "I"); - $testAnnotationsPhp .= "\t * @return void\n"; - $testAnnotationsPhp .= "\t */\n"; - - return $testAnnotationsPhp; - } - /** * Creates a PHP string based on a block. * Concatenates the Test Annotations PHP and Test PHP for a single Test. * @param array $testsObject * @return string + * @throws TestReferenceException */ private function generateTestsPhp($testsObject) { @@ -1218,7 +1149,7 @@ private function generateTestsPhp($testsObject) foreach ($testsObject as $test) { $testName = $test->getName(); $testName = str_replace(' ', '', $testName); - $testAnnotations = $this->generateTestAnnotationsPhp($test->getAnnotations()); + $testAnnotations = $this->generateAnnotationsPhp($test->getAnnotations(), "Test"); $dependencies = 'AcceptanceTester $I'; try { $steps = $this->generateStepsPhp($test->getOrderedActions(), $test->getCustomData()); From cef7b0b428c0876bcaa0a7a2318412ae96be646b Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Wed, 15 Nov 2017 15:06:50 -0600 Subject: [PATCH 24/29] MQE-235: Fixed additional merge conflict. # dev/tests/verification/Resources/PersistedReplacementCest.txt --- .../Resources/PersistedReplacementCest.txt | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/dev/tests/verification/Resources/PersistedReplacementCest.txt b/dev/tests/verification/Resources/PersistedReplacementCest.txt index 26f83f814..e30c6bc13 100644 --- a/dev/tests/verification/Resources/PersistedReplacementCest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementCest.txt @@ -44,9 +44,9 @@ class PersistedReplacementCest $createdData = new DataPersistenceHandler($simpleData); $createdData->createEntity(); $I->amGoingTo("create entity that has the mergeKey: uniqueData"); - $UniquePerson = DataObjectHandler::getInstance()->getObject("UniquePerson"); - $uniqueData = new DataPersistenceHandler($UniquePerson); - $uniqueData->createEntity(); + $UniquePerson = DataObjectHandler::getInstance()->getObject("UniquePerson"); + $uniqueData = new DataPersistenceHandler($UniquePerson); + $uniqueData->createEntity(); $I->fillField("#selector", "StringBefore " . $createdData->getCreatedDataByName('firstname') . " StringAfter"); $I->fillField("#" . $createdData->getCreatedDataByName('firstname'), "input"); $I->dragAndDrop("#" . $createdData->getCreatedDataByName('firstname'), $createdData->getCreatedDataByName('lastname')); @@ -55,15 +55,15 @@ class PersistedReplacementCest $I->searchAndMultiSelectOption("#selector", [$createdData->getCreatedDataByName('firstname'), $createdData->getCreatedDataByName('lastname')]); $I->fillField("#selector", "John " . $createdData->getCreatedDataByName('firstname') . " stringLiteral"); $I->searchAndMultiSelectOption("#selector", [$createdData->getCreatedDataByName('firstname'), "John", "stringLiteral"]); - $I->assertStringStartsWith("W", $uniqueData->getCreatedDataByName('firstname') . " " . $uniqueData->getCreatedDataByName('lastname'), "pass"); - $I->assertEquals($this->createData1->getCreatedDataByName('lastname'), $this->createData1->getCreatedDataByName('lastname'), "pass"); - $I->assertFileExists("../Data/SampleData.xml", "pass"); - $I->assertArraySubset([$this->createData1->getCreatedDataByName('lastname') . "", "" . $this->createData1->getCreatedDataByName('firstname')], [$this->createData1->getCreatedDataByName('lastname') . "", "" . $this->createData1->getCreatedDataByName('firstname') . "", "1"], "pass"); - $I->assertArraySubset([$uniqueData->getCreatedDataByName('firstname') . "", "" . $uniqueData->getCreatedDataByName('lastname')], [$uniqueData->getCreatedDataByName('firstname') . "", "" . $uniqueData->getCreatedDataByName('lastname') . "", "1"], "pass"); - $I->assertArrayHasKey("lastname", ['lastname' => $this->createData1->getCreatedDataByName('lastname') . "", 'firstname' => "" . $this->createData1->getCreatedDataByName('firstname')], "pass"); - $I->assertArrayHasKey("lastname", ['lastname' => $uniqueData->getCreatedDataByName('lastname') . "", 'firstname' => "" . $uniqueData->getCreatedDataByName('firstname')], "pass"); - $I->fail($uniqueData->getCreatedDataByName('firstname') . " " . $uniqueData->getCreatedDataByName('lastname')); - $I->fail($this->createData1->getCreatedDataByName('firstname') . " " . $this->createData1->getCreatedDataByName('lastname')); - $I->assertStringStartsNotWith("D", $this->createData1->getCreatedDataByName('lastname') . ", " . $this->createData1->getCreatedDataByName('firstname'), "fail"); + $I->assertStringStartsNotWith("D", $this->createData1->getCreatedDataByName('lastname') . ", " . $this->createData1->getCreatedDataByName('firstname'), "fail"); + $I->assertStringStartsWith("W", $uniqueData->getCreatedDataByName('firstname') . " " . $uniqueData->getCreatedDataByName('lastname'), "pass"); + $I->assertEquals($this->createData1->getCreatedDataByName('lastname'), $this->createData1->getCreatedDataByName('lastname'), "pass"); + $I->assertFileExists("../Data/SampleData.xml", "pass"); + $I->assertArraySubset([$this->createData1->getCreatedDataByName('lastname'), $this->createData1->getCreatedDataByName('firstname')], [$this->createData1->getCreatedDataByName('lastname'), $this->createData1->getCreatedDataByName('firstname'), "1"], "pass"); + $I->assertArraySubset([$uniqueData->getCreatedDataByName('firstname'), $uniqueData->getCreatedDataByName('lastname')], [$uniqueData->getCreatedDataByName('firstname'), $uniqueData->getCreatedDataByName('lastname'), "1"], "pass"); + $I->assertArrayHasKey("lastname", ['lastname' => $this->createData1->getCreatedDataByName('lastname'), 'firstname' => $this->createData1->getCreatedDataByName('firstname')], "pass"); + $I->assertArrayHasKey("lastname", ['lastname' => $uniqueData->getCreatedDataByName('lastname'), 'firstname' => $uniqueData->getCreatedDataByName('firstname')], "pass"); + $I->fail($uniqueData->getCreatedDataByName('firstname') . " " . $uniqueData->getCreatedDataByName('lastname')); + $I->fail($this->createData1->getCreatedDataByName('firstname') . " " . $this->createData1->getCreatedDataByName('lastname')); } } From 00af5c9b3764ebd78460b771589d56ba6170e737 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Thu, 16 Nov 2017 13:39:27 -0600 Subject: [PATCH 25/29] MQE-235: added codeception Asserts module functions in framework. --- .../verification/Resources/AssertCest.txt | 102 ++++++++++++ .../Resources/BasicFunctionalCest.txt | 44 ----- .../Resources/PersistedReplacementCest.txt | 14 -- .../TestModule/Cest/AssertCest.xml | 81 ++++++++++ .../TestModule/Cest/BasicFunctionalCest.xml | 45 ------ .../Cest/PersistedReplacementCest.xml | 14 -- .../Tests/AssertGenerationTest.php | 38 +++++ .../Test/etc/testSchema.xsd | 141 ++++++++-------- .../Util/TestGenerator.php | 150 ++++++++++-------- 9 files changed, 387 insertions(+), 242 deletions(-) create mode 100644 dev/tests/verification/Resources/AssertCest.txt create mode 100644 dev/tests/verification/TestModule/Cest/AssertCest.xml create mode 100644 dev/tests/verification/Tests/AssertGenerationTest.php diff --git a/dev/tests/verification/Resources/AssertCest.txt b/dev/tests/verification/Resources/AssertCest.txt new file mode 100644 index 000000000..fd2fe2259 --- /dev/null +++ b/dev/tests/verification/Resources/AssertCest.txt @@ -0,0 +1,102 @@ +amGoingTo("create entity that has the mergeKey: createData1"); + $ReplacementPerson = DataObjectHandler::getInstance()->getObject("ReplacementPerson"); + $this->createData1 = new DataPersistenceHandler($ReplacementPerson); + $this->createData1->createEntity(); + } + + /** + * @Parameter(name = "AcceptanceTester", value="$I") + * @param AcceptanceTester $I + * @return void + */ + public function AssertTest(AcceptanceTester $I) + { + $I->amGoingTo("create entity that has the mergeKey: createData2"); + $UniquePerson = DataObjectHandler::getInstance()->getObject("UniquePerson"); + $createData2 = new DataPersistenceHandler($UniquePerson); + $createData2->createEntity(); + $text = $I->grabTextFrom(".copyright>span"); + $I->comment("asserts without variable replacement"); + $I->assertArrayHasKey("apple", ['orange' => 2, 'apple' => 1], "pass"); + $I->assertArrayNotHasKey("kiwi", ['orange' => 2, 'apple' => 1], "pass"); + $I->assertArraySubset([1, 2], [1, 2, 3, 5], "pass"); + $I->assertContains("ab", ['item1' => 'a', 'item2' => 'ab'], "pass"); + $I->assertCount(2, ['a', 'b'], "pass"); + $I->assertEmpty([], "pass"); + $I->assertEquals($text, "Copyright © 2013-2017 Magento, Inc. All rights reserved.", "pass"); + $I->assertEquals("Copyright © 2013-2017 Magento, Inc. All rights reserved.", $text, "pass"); + $I->assertFalse(false, "pass"); + $I->assertFileNotExists("/out.txt", "pass"); + $I->assertFileNotExists($text, "pass"); + $I->assertGreaterOrEquals(2, 5, "pass"); + $I->assertGreaterThan(2, 5, "pass"); + $I->assertGreaterThanOrEqual(2, 5, "pass"); + $I->assertInternalType("string", "xyz", "pass"); + $I->assertInternalType("int", 21, "pass"); + $I->assertInternalType("string", $text, "pass"); + $I->assertLessOrEquals(5, 2, "pass"); + $I->assertLessThan(5, 2, "pass"); + $I->assertLessThanOrEqual(5, 2, "pass"); + $I->assertNotContains("bc", ['item1' => 'a', 'item2' => 'ab'], "pass"); + $I->assertNotContains("bc", $text, "pass"); + $I->assertNotEmpty([1, 2], "pass"); + $I->assertNotEmpty($text, "pass"); + $I->assertNotEquals(2, 5, "pass", 0); + $I->assertNotNull("abc", "pass"); + $I->assertNotNull($text, "pass"); + $I->assertNotRegExp("/foo/", "bar", "pass"); + $I->assertNotSame("log", "tag", "pass"); + $I->assertRegExp("/foo/", "foo", "pass"); + $I->assertSame("bar", "bar", "pass"); + $I->assertStringStartsNotWith("a", "banana", "pass"); + $I->assertStringStartsWith("a", "apple", "pass"); + $I->assertTrue(true, "pass"); + $I->comment("string type that use created data"); + $I->assertStringStartsWith("D", $this->createData1->getCreatedDataByName('lastname') . ", " . $this->createData1->getCreatedDataByName('firstname'), "fail"); + $I->assertStringStartsNotWith("W", $createData2->getCreatedDataByName('firstname') . " " . $createData2->getCreatedDataByName('lastname'), "pass"); + $I->assertEquals($this->createData1->getCreatedDataByName('lastname'), $this->createData1->getCreatedDataByName('lastname'), "pass"); + $I->comment("array type that use created data"); + $I->assertArraySubset([$this->createData1->getCreatedDataByName('lastname'), $this->createData1->getCreatedDataByName('firstname')], [$this->createData1->getCreatedDataByName('lastname'), $this->createData1->getCreatedDataByName('firstname'), "1"], "pass"); + $I->assertArraySubset([$createData2->getCreatedDataByName('firstname'), $createData2->getCreatedDataByName('lastname')], [$createData2->getCreatedDataByName('firstname'), $createData2->getCreatedDataByName('lastname'), "1"], "pass"); + $I->assertArrayHasKey("lastname", ['lastname' => $this->createData1->getCreatedDataByName('lastname'), 'firstname' => $this->createData1->getCreatedDataByName('firstname')], "pass"); + $I->assertArrayHasKey("lastname", ['lastname' => $createData2->getCreatedDataByName('lastname'), 'firstname' => $createData2->getCreatedDataByName('firstname')], "pass"); + $I->assertInstanceOf(User::class, $text, "pass"); + $I->assertNotInstanceOf(User::class, 21, "pass"); + $I->assertFileExists($text, "pass"); + $I->assertFileExists("AssertCest.php", "pass"); + $I->assertIsEmpty($text, "pass"); + $I->assertNull($text, "pass"); + $I->expectException(new MyException('exception msg'), function() {$this->doSomethingBad();}); + $I->fail("fail"); + $I->fail($createData2->getCreatedDataByName('firstname') . " " . $createData2->getCreatedDataByName('lastname')); + $I->fail($this->createData1->getCreatedDataByName('firstname') . " " . $this->createData1->getCreatedDataByName('lastname')); + } +} diff --git a/dev/tests/verification/Resources/BasicFunctionalCest.txt b/dev/tests/verification/Resources/BasicFunctionalCest.txt index 29f2d1cad..b7afc27d9 100644 --- a/dev/tests/verification/Resources/BasicFunctionalCest.txt +++ b/dev/tests/verification/Resources/BasicFunctionalCest.txt @@ -129,49 +129,5 @@ class BasicFunctionalCest $I->waitForElementVisible(".functionalTestSelector", 30); $I->waitForJS("someJsFunction", 30); $I->waitForText("someInput", 30, ".functionalTestSelector"); - $I->assertArrayHasKey("apple", ['orange' => "2", 'apple' => "1"], "pass"); - $I->assertArrayNotHasKey("kiwi", ['orange' => "2", 'apple' => "1"], "pass"); - $I->assertArraySubset(["1", "2"], ["5", "3", "2", "1"], "pass"); - $I->assertContains("ab", ['item1' => 'a', 'item2' => 'ab'], "pass"); - $I->assertCount("2", ['a', 'b'], "pass"); - $I->assertEmpty("''", "pass"); - $I->assertEmpty("[]", "pass"); - $I->assertEmpty($value1, "pass"); - $I->assertEquals("abc", "abc", "pass"); - $I->assertEquals("2", $value1, "pass"); - $I->assertFalse($value1, "pass"); - $I->assertFileExists("/out.txt", "pass"); - $I->assertFileExists($value1, "pass"); - $I->assertFileNotExists("/out.txt", "pass"); - $I->assertFileNotExists("file", "pass"); - $I->assertGreaterOrEquals("5", "2", "pass"); - $I->assertGreaterThan("5", "2", "pass"); - $I->assertGreaterThanOrEqual("5", "2", "pass"); - $I->assertInstanceOf(User::class, $value1, "pass"); - $I->assertInternalType("string", "xyz", "pass"); - $I->assertInternalType("xyz", "pass"); - $I->assertInternalType($value1, "pass"); - $I->assertIsEmpty($value1, "pass"); - $I->assertLessOrEquals("2", "5", "pass"); - $I->assertLessThan("2", "5", "pass"); - $I->assertLessThanOrEqual("2", "5", "pass"); - $I->assertNotContains("bc", ['item1' => 'a', 'item2' => 'ab'], "pass"); - $I->assertNotContains("bc", "pass"); - $I->assertNotEmpty("[1, 2]", "pass"); - $I->assertNotEmpty($value1, "pass"); - $I->assertNotEquals("2", "5", "pass"); - $I->assertNotInstanceOf("21", "pass"); - $I->assertNotNull("abc", "pass"); - $I->assertNotNull($value1, "pass"); - $I->assertNotRegExp("/foo/", "bar", "pass"); - $I->assertNotSame("log", "tag", "pass"); - $I->assertNull($value1, "pass"); - $I->assertRegExp("/foo/", "foo", "pass"); - $I->assertSame("bar", "bar", "pass"); - $I->assertStringStartsNotWith("a", "banana", "pass"); - $I->assertStringStartsWith("a", "apple", "pass"); - $I->assertTrue("true", "pass"); - $I->expectException(new MyException('exception msg'), function() {$this->doSomethingBad();}); - $I->fail("fail"); } } diff --git a/dev/tests/verification/Resources/PersistedReplacementCest.txt b/dev/tests/verification/Resources/PersistedReplacementCest.txt index e30c6bc13..4ff8d853e 100644 --- a/dev/tests/verification/Resources/PersistedReplacementCest.txt +++ b/dev/tests/verification/Resources/PersistedReplacementCest.txt @@ -43,10 +43,6 @@ class PersistedReplacementCest $simpleData = DataObjectHandler::getInstance()->getObject("simpleData"); $createdData = new DataPersistenceHandler($simpleData); $createdData->createEntity(); - $I->amGoingTo("create entity that has the mergeKey: uniqueData"); - $UniquePerson = DataObjectHandler::getInstance()->getObject("UniquePerson"); - $uniqueData = new DataPersistenceHandler($UniquePerson); - $uniqueData->createEntity(); $I->fillField("#selector", "StringBefore " . $createdData->getCreatedDataByName('firstname') . " StringAfter"); $I->fillField("#" . $createdData->getCreatedDataByName('firstname'), "input"); $I->dragAndDrop("#" . $createdData->getCreatedDataByName('firstname'), $createdData->getCreatedDataByName('lastname')); @@ -55,15 +51,5 @@ class PersistedReplacementCest $I->searchAndMultiSelectOption("#selector", [$createdData->getCreatedDataByName('firstname'), $createdData->getCreatedDataByName('lastname')]); $I->fillField("#selector", "John " . $createdData->getCreatedDataByName('firstname') . " stringLiteral"); $I->searchAndMultiSelectOption("#selector", [$createdData->getCreatedDataByName('firstname'), "John", "stringLiteral"]); - $I->assertStringStartsNotWith("D", $this->createData1->getCreatedDataByName('lastname') . ", " . $this->createData1->getCreatedDataByName('firstname'), "fail"); - $I->assertStringStartsWith("W", $uniqueData->getCreatedDataByName('firstname') . " " . $uniqueData->getCreatedDataByName('lastname'), "pass"); - $I->assertEquals($this->createData1->getCreatedDataByName('lastname'), $this->createData1->getCreatedDataByName('lastname'), "pass"); - $I->assertFileExists("../Data/SampleData.xml", "pass"); - $I->assertArraySubset([$this->createData1->getCreatedDataByName('lastname'), $this->createData1->getCreatedDataByName('firstname')], [$this->createData1->getCreatedDataByName('lastname'), $this->createData1->getCreatedDataByName('firstname'), "1"], "pass"); - $I->assertArraySubset([$uniqueData->getCreatedDataByName('firstname'), $uniqueData->getCreatedDataByName('lastname')], [$uniqueData->getCreatedDataByName('firstname'), $uniqueData->getCreatedDataByName('lastname'), "1"], "pass"); - $I->assertArrayHasKey("lastname", ['lastname' => $this->createData1->getCreatedDataByName('lastname'), 'firstname' => $this->createData1->getCreatedDataByName('firstname')], "pass"); - $I->assertArrayHasKey("lastname", ['lastname' => $uniqueData->getCreatedDataByName('lastname'), 'firstname' => $uniqueData->getCreatedDataByName('firstname')], "pass"); - $I->fail($uniqueData->getCreatedDataByName('firstname') . " " . $uniqueData->getCreatedDataByName('lastname')); - $I->fail($this->createData1->getCreatedDataByName('firstname') . " " . $this->createData1->getCreatedDataByName('lastname')); } } diff --git a/dev/tests/verification/TestModule/Cest/AssertCest.xml b/dev/tests/verification/TestModule/Cest/AssertCest.xml new file mode 100644 index 000000000..4028501c1 --- /dev/null +++ b/dev/tests/verification/TestModule/Cest/AssertCest.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/verification/TestModule/Cest/BasicFunctionalCest.xml b/dev/tests/verification/TestModule/Cest/BasicFunctionalCest.xml index f18b72ff8..28578bd44 100644 --- a/dev/tests/verification/TestModule/Cest/BasicFunctionalCest.xml +++ b/dev/tests/verification/TestModule/Cest/BasicFunctionalCest.xml @@ -113,51 +113,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml b/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml index 9d23e60c3..663c51ef7 100644 --- a/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml +++ b/dev/tests/verification/TestModule/Cest/PersistedReplacementCest.xml @@ -14,7 +14,6 @@
- @@ -24,19 +23,6 @@ - - - - - - - - - - - - - diff --git a/dev/tests/verification/Tests/AssertGenerationTest.php b/dev/tests/verification/Tests/AssertGenerationTest.php new file mode 100644 index 000000000..ea0857228 --- /dev/null +++ b/dev/tests/verification/Tests/AssertGenerationTest.php @@ -0,0 +1,38 @@ +getObject(self::BASIC_ASSERT_CEST); + $test = TestGenerator::getInstance(null, [$cest]); + $test->createAllCestFiles(); + + $cestFile = $test->getExportDir() . + DIRECTORY_SEPARATOR . + self::BASIC_ASSERT_CEST . + ".php"; + + $this->assertTrue(file_exists($cestFile)); + + $this->assertFileEquals( + self::RESOURCES_PATH . DIRECTORY_SEPARATOR . self::BASIC_ASSERT_CEST . ".txt", + $cestFile + ); + } +} diff --git a/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd b/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd index 5c1088d6c..d54eb1060 100644 --- a/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd +++ b/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd @@ -1565,9 +1565,9 @@ - - - + + + @@ -1580,9 +1580,9 @@ - - - + + + @@ -1594,10 +1594,10 @@ - - - - + + + + @@ -1611,9 +1611,9 @@ - - - + + + @@ -1626,9 +1626,9 @@ - - - + + + @@ -1641,7 +1641,7 @@ - + @@ -1654,9 +1654,9 @@ + - - + @@ -1670,7 +1670,7 @@ - + @@ -1683,7 +1683,7 @@ - + @@ -1696,7 +1696,7 @@ - + @@ -1709,7 +1709,9 @@ + + @@ -1722,9 +1724,9 @@ + - - + @@ -1737,9 +1739,9 @@ + - - + @@ -1751,8 +1753,10 @@ - - + + + + @@ -1764,10 +1768,10 @@ - + - + @@ -1780,7 +1784,7 @@ - + @@ -1793,9 +1797,9 @@ + - - + @@ -1808,9 +1812,9 @@ + - - + @@ -1823,9 +1827,9 @@ + - - + @@ -1838,9 +1842,9 @@ - - - + + + @@ -1853,7 +1857,7 @@ - + @@ -1866,9 +1870,9 @@ + - - + @@ -1882,9 +1886,9 @@ + - - + @@ -1897,7 +1901,7 @@ - + @@ -1910,9 +1914,9 @@ + - - + @@ -1925,9 +1929,9 @@ + - - + @@ -1940,7 +1944,7 @@ - + @@ -1953,9 +1957,9 @@ + - - + @@ -1968,9 +1972,9 @@ + - - + @@ -1983,9 +1987,9 @@ + - - + @@ -1998,9 +2002,9 @@ + - - + @@ -2013,7 +2017,7 @@ - + @@ -2025,8 +2029,10 @@ - - + + + + @@ -2045,4 +2051,15 @@ + + + + + + + + + + + diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 18b9a0582..4a911b3e4 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -370,14 +370,10 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) $visible = null; $assertExpected = null; - $assertExpectedArray = null; $assertActual = null; - $assertActualArray = null; $assertMessage = null; - $assertFunction = null; $assertIsStrict = null; $assertDelta = null; - $class = null; if (isset($customActionAttributes['returnVariable'])) { $returnVariable = $customActionAttributes['returnVariable']; @@ -393,21 +389,26 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) } elseif (isset($customActionAttributes['url'])) { $input = $this->addUniquenessFunctionCall($customActionAttributes['url']); } - if (isset($customActionAttributes['expected'])) { - $assertExpected = $this->addUniquenessFunctionCall($customActionAttributes['expected']); + $assertExpected = $this->resolveValueByType( + $customActionAttributes['expected'], + isset($customActionAttributes['expectedType']) ? $customActionAttributes['expectedType'] : null + ); } if (isset($customActionAttributes['actual'])) { - $assertActual = $this->addUniquenessFunctionCall($customActionAttributes['actual']); + $assertActual = $this->resolveValueByType( + $customActionAttributes['actual'], + isset($customActionAttributes['actualType']) ? $customActionAttributes['actualType'] : null + ); } if (isset($customActionAttributes['message'])) { $assertMessage = $this->addUniquenessFunctionCall($customActionAttributes['message']); } - if (isset($customActionAttributes['expectedVariable'])) { - $assertExpected = $this->addDollarSign($customActionAttributes['expectedVariable']); + if (isset($customActionAttributes['delta'])) { + $assertDelta = $this->resolveValueByType($customActionAttributes['delta'], "float"); } - if (isset($customActionAttributes['actualVariable'])) { - $assertActual = $this->addDollarSign($customActionAttributes['actualVariable']); + if (isset($customActionAttributes['strict'])) { + $assertIsStrict = $this->resolveValueByType($customActionAttributes['strict'], "bool"); } if (isset($customActionAttributes['time'])) { @@ -425,22 +426,6 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) $customActionAttributes['parameterArray'] ) . "]"; } - if (isset($customActionAttributes['expectedArray'])) { - // validate the param array is in the correct format - $this->validateParameterArray($customActionAttributes['expectedArray']); - - $assertExpectedArray = "[" - . $this->addUniquenessToParamArray($customActionAttributes['expectedArray']) - . "]"; - } - if (isset($customActionAttributes['actualArray'])) { - // validate the param array is in the correct format - $this->validateParameterArray($customActionAttributes['actualArray']); - - $assertActualArray = "[" - . $this->addUniquenessToParamArray($customActionAttributes['actualArray']) - . "]"; - } if (isset($customActionAttributes['requiredAction'])) { $requiredAction = $customActionAttributes['requiredAction']; @@ -475,10 +460,6 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) $function = $customActionAttributes['function']; } - if (isset($customActionAttributes['class'])) { - $class = $customActionAttributes['class']; - } - if (isset($customActionAttributes['html'])) { $html = $customActionAttributes['html']; } @@ -964,43 +945,27 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) case "assertLessThan": case "assertLessThanOrEqual": case "assertNotEquals": - + case "assertInstanceOf": + case "assertNotInstanceOf": case "assertNotRegExp": case "assertNotSame": case "assertRegExp": case "assertSame": case "assertStringStartsNotWith": case "assertStringStartsWith": - $testSteps .= $this->wrapFunctionCall( - $actor, - $actionName, - $assertExpected, - $assertActual, - $assertMessage, - $assertDelta - ); - break; - case "assertInstanceOf": - case "assertNotInstanceOf": - $testSteps .= $this->wrapFunctionCall( - $actor, - $actionName, - $class, - $assertActual, - $assertMessage - ); - break; case "assertArrayHasKey": case "assertArrayNotHasKey": case "assertCount": case "assertContains": case "assertNotContains": + case "expectException": $testSteps .= $this->wrapFunctionCall( $actor, $actionName, $assertExpected, - $assertActualArray, - $assertMessage + $assertActual, + $assertMessage, + $assertDelta ); break; case "assertEmpty": @@ -1023,20 +988,12 @@ private function generateStepsPhp($stepsObject, $stepsData, $hookObject = false) $testSteps .= $this->wrapFunctionCall( $actor, $actionName, - $assertExpectedArray, - $assertActualArray, + $assertExpected, + $assertActual, $assertIsStrict, $assertMessage ); break; - case "expectException": - $testSteps .= $this->wrapFunctionCall( - $actor, - $actionName, - $class, - $function - ); - break; case "fail": $testSteps .= $this->wrapFunctionCall( $actor, @@ -1488,4 +1445,71 @@ private function validateParameterArray($paramArray) throw new TestReferenceException("parameterArray must begin with `[` and end with `]"); } } + + /** + * @param string $value + * @param string $type + * @return string + */ + private function resolveValueByType($value, $type) + { + if (null === $value) { + return null; + } + if (null === $type) { + $type = 'const'; + } + if ($type == "string") { + return $this->addUniquenessFunctionCall($value); + } elseif ($type == "bool") { + return $this->toBoolean($value) ? "true" : "false"; + } elseif ($type == "int" || $type == "float") { + return $this->toNumber($value); + } elseif ($type == "array") { + $this->validateParameterArray($value); + return "[" . $this->addUniquenessToParamArray($value) . "]"; + } elseif ($type == "variable") { + return $this->addDollarSign($value); + } else { + return $value; + } + } + + /** + * Convert input string to boolean equivalent. + * + * @param string $inStr + * @return bool|null + */ + private function toBoolean($inStr) + { + return boolval($this->stripQuotes($inStr)); + } + + /** + * Convert input string to number equivalent. + * + * @param string $inStr + * @return int|float|null + */ + private function toNumber($inStr) + { + $outStr = $this->stripQuotes($inStr); + if (strpos($outStr, localeconv()['decimal_point']) === false) { + return intval($outStr); + } else { + return floatval($outStr); + } + } + + /** + * Strip single or double quotes from begin and end of input string. + * + * @param string $inStr + * @return string + */ + private function stripQuotes($inStr) { + $unquoted = preg_replace('/^(\'(.*)\'|"(.*)")$/', '$2$3', $inStr); + return $unquoted; + } } From 4feb7936a80ca4be064e2bf27af6f133499a3199 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Thu, 16 Nov 2017 14:57:05 -0600 Subject: [PATCH 26/29] MQE-235: added codeception Asserts module functions in framework. --- dev/tests/verification/TestModule/Cest/AssertCest.xml | 4 ++-- .../FunctionalTestingFramework/Util/TestGenerator.php | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/dev/tests/verification/TestModule/Cest/AssertCest.xml b/dev/tests/verification/TestModule/Cest/AssertCest.xml index 4028501c1..9444da9f6 100644 --- a/dev/tests/verification/TestModule/Cest/AssertCest.xml +++ b/dev/tests/verification/TestModule/Cest/AssertCest.xml @@ -27,13 +27,13 @@ - + - + diff --git a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php index 4a911b3e4..94e1117ac 100644 --- a/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php +++ b/src/Magento/FunctionalTestingFramework/Util/TestGenerator.php @@ -1371,7 +1371,7 @@ private function stripWrappedQuotes($input) */ private function addDollarSign($input) { - return sprintf("$%s", $input); + return sprintf("$%s", ltrim($this->stripQuotes($input), '$')); } // @codingStandardsIgnoreStart @@ -1447,6 +1447,8 @@ private function validateParameterArray($paramArray) } /** + * Resolve value based on type. + * * @param string $value * @param string $type * @return string @@ -1508,7 +1510,8 @@ private function toNumber($inStr) * @param string $inStr * @return string */ - private function stripQuotes($inStr) { + private function stripQuotes($inStr) + { $unquoted = preg_replace('/^(\'(.*)\'|"(.*)")$/', '$2$3', $inStr); return $unquoted; } From 76f9cdc4c07963342d19ca7bd7927120f01d6ad1 Mon Sep 17 00:00:00 2001 From: Ian Meron Date: Mon, 20 Nov 2017 10:13:29 -0600 Subject: [PATCH 27/29] MQE-434: Create operation api unit tests - add new unit tests - refactor old unit test to use new mock tool - AspectMock --- .../OperationDataArrayResolverTest.php | 347 ++++++++++++++++++ .../Test/Util/ActionMergeUtilTest.php | 13 +- .../Util/DataObjectHandlerReflectionUtil.php | 47 --- .../unit/Util/EntityDataObjectBuilder.php | 117 ++++++ .../ObjectHandlerReflectionUtilInterface.php | 24 -- .../unit/Util/OperationDefinitionBuilder.php | 120 ++++++ .../unit/Util/OperationElementBuilder.php | 192 ++++++++++ .../Test/Util/ActionGroupObjectExtractor.php | 2 +- 8 files changed, 780 insertions(+), 82 deletions(-) create mode 100644 dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php delete mode 100644 dev/tests/unit/Util/DataObjectHandlerReflectionUtil.php create mode 100644 dev/tests/unit/Util/EntityDataObjectBuilder.php delete mode 100644 dev/tests/unit/Util/ObjectHandlerReflectionUtilInterface.php create mode 100644 dev/tests/unit/Util/OperationDefinitionBuilder.php create mode 100644 dev/tests/unit/Util/OperationElementBuilder.php diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php new file mode 100644 index 000000000..513c80e9b --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Persist/OperationDataArrayResolverTest.php @@ -0,0 +1,347 @@ + [ + "name" => "Hopper", + "address" => ["city" => "Hawkins", "state" => "Indiana", "zip" => 78758], + "isPrimary" => true, + "gpa" => 3.5, + "phone" => 5555555 + ]]; + + const NESTED_METADATA_ARRAY_RESULT = ["parentType" => [ + "name" => "Hopper", + "isPrimary" => true, + "gpa" => 3.5, + "phone" => 5555555, + "address" => [ + ["city" => "Hawkins", "state" => "Indiana", "zip" => 78758], + ["city" => "Austin", "state" => "Texas", "zip" => 78701], + ] + ]]; + + /** + * Test a basic metadata resolve between primitive values and a primitive data set + * + * stringField + * intField + * boolField + * doubleField + * + */ + public function testBasicPrimitiveMetadataResolve() + { + // set up data object + $entityObjectBuilder = new EntityDataObjectBuilder(); + $testDataObject = $entityObjectBuilder->build(); + + // set up meta data operation elements + $operationElementBuilder = new OperationElementBuilder(); + $operationElement = $operationElementBuilder->build(); + + // resolve data object and metadata array + $operationDataArrayResolver = new OperationDataArrayResolver(); + $result = $operationDataArrayResolver->resolveOperationDataArray( + $testDataObject, + [$operationElement], + 'create' + ); + + // assert on result + $expectedResult = ["testType" => [ + "name" => "Hopper", + "gpa" => 3.5, + "phone" => 5555555, + "isPrimary" => true + ]]; + + $this->assertEquals($expectedResult, $result); + } + + /** + * Test a nested metadata operation resolve: + * + * someField + * objectRef + * + */ + public function testNestedMetadataResolve() + { + // set up data objects + $entityDataObjBuilder = new EntityDataObjectBuilder(); + $parentDataObject = $entityDataObjBuilder + ->withName("parentObject") + ->withType("parentType") + ->withLinkedEntities(['childObject' => 'childType']) + ->build(); + + $childDataObject = $entityDataObjBuilder + ->withName("childObject") + ->withType("childType") + ->withDataFields(["city" => "Hawkins", "state" => "Indiana", "zip" => "78758"]) + ->build(); + + // mock data object handler + $mockDOHInstance = AspectMock::double(DataObjectHandler::class, ['getObject' => $childDataObject])->make(); + AspectMock::double(DataObjectHandler::class, ['getInstance' => $mockDOHInstance]); + + // set up metadata objects + $parentOpElementBuilder = new OperationElementBuilder(); + $parentElement = $parentOpElementBuilder + ->withKey("parentType") + ->withType("parentType") + ->addFields(["address" => "childType"]) + ->build(); + + $operationDefinitionBuilder = new OperationDefinitionBuilder(); + $childOperationDefinition = $operationDefinitionBuilder + ->withName("createChildType") + ->withOperation("create") + ->withType("childType") + ->withMetadata([ + "city" => "string", + "state" => "string", + "zip" => "integer" + ])->build(); + + // mock meta data object handler + $mockDOHInstance = AspectMock::double( + OperationDefinitionObjectHandler::class, + ['getObject' => $childOperationDefinition] + )->make(); + AspectMock::double(OperationDefinitionObjectHandler::class, ['getInstance' => $mockDOHInstance]); + + // resolve data object and metadata array + $operationResolver = new OperationDataArrayResolver(); + $result = $operationResolver->resolveOperationDataArray($parentDataObject, [$parentElement], "create", false); + + // assert on the result + $this->assertEquals(self::NESTED_METADATA_EXPECTED_RESULT, $result); + } + + /** + * Test a nested metadata operation: + * + * someField + * + * anotherField + * + * + */ + public function testNestedMetadata() + { + // set up data objects + $entityDataObjectBuilder = new EntityDataObjectBuilder(); + $parentDataObject = $entityDataObjectBuilder + ->withName("parentObject") + ->withType("parentType") + ->withLinkedEntities(['childObject' => 'childType']) + ->build(); + + $childDataObject = $entityDataObjectBuilder + ->withName("childObject") + ->withType("childType") + ->withDataFields(["city" => "Hawkins", "state" => "Indiana", "zip" => "78758"]) + ->build(); + + // mock data object handler + $mockDOHInstance = AspectMock::double(DataObjectHandler::class, ['getObject' => $childDataObject])->make(); + AspectMock::double(DataObjectHandler::class, ['getInstance' => $mockDOHInstance]); + + // set up metadata objects + $childOpElementBuilder = new OperationElementBuilder(); + $childElement = $childOpElementBuilder + ->withKey("address") + ->withType("childType") + ->withFields(["city" => "string", "state" => "string", "zip" => "integer"]) + ->build(); + + $parentOpElementBuilder = new OperationElementBuilder(); + $parentElement = $parentOpElementBuilder + ->withKey("parentType") + ->withType("parentType") + ->addElements(["address" => $childElement]) + ->build(); + + // resolve data object and metadata array + $operationResolver = new OperationDataArrayResolver(); + $result = $operationResolver->resolveOperationDataArray($parentDataObject, [$parentElement], "create", false); + + // assert on the result + $this->assertEquals(self::NESTED_METADATA_EXPECTED_RESULT, $result); + } + + /** + * Test a nested metadata operation with a declared object: + * + * someField + * + * + * anotherField + * + * + */ + public function testNestedMetadataArrayOfObjects() + { + // set up data objects + $entityDataObjectBuilder = new EntityDataObjectBuilder(); + $parentDataObject = $entityDataObjectBuilder + ->withName("parentObject") + ->withType("parentType") + ->withLinkedEntities(['childObject1' => 'childType', 'childObject2' => 'childType']) + ->build(); + + // mock data object handler + $mockDOHInstance = AspectMock::double(DataObjectHandler::class, ["getObject" => function ($name) { + $entityDataObjectBuilder = new EntityDataObjectBuilder(); + + if ($name == "childObject1") { + return $entityDataObjectBuilder + ->withName("childObject1") + ->withType("childType") + ->withDataFields(["city" => "Hawkins", "state" => "Indiana", "zip" => "78758"]) + ->build(); + } + + if ($name == "childObject2") { + return $entityDataObjectBuilder + ->withName("childObject2") + ->withType("childType") + ->withDataFields(["city" => "Austin", "state" => "Texas", "zip" => "78701"]) + ->build(); + } + }])->make(); + AspectMock::double(DataObjectHandler::class, ['getInstance' => $mockDOHInstance]); + + // set up metadata objects + $childOpElementBuilder = new OperationElementBuilder(); + $childElement = $childOpElementBuilder + ->withKey("childType") + ->withType("childType") + ->withFields(["city" => "string", "state" => "string", "zip" => "integer"]) + ->build(); + + $arrayOpElementBuilder = new OperationElementBuilder(); + $arrayElement = $arrayOpElementBuilder + ->withKey("address") + ->withType("childType") + ->withFields([]) + ->withElementType(OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY) + ->withNestedElements(["childType" => $childElement]) + ->build(); + + $parentOpElementBuilder = new OperationElementBuilder(); + $parentElement = $parentOpElementBuilder + ->withKey("parentType") + ->withType("parentType") + ->addElements(["address" => $arrayElement]) + ->build(); + + // resolve data object and metadata array + $operationResolver = new OperationDataArrayResolver(); + $result = $operationResolver->resolveOperationDataArray($parentDataObject, [$parentElement], "create", false); + + // Do assert on result here + $this->assertEquals(self::NESTED_METADATA_ARRAY_RESULT, $result); + } + + /** + * Test a nested metadata operation with a value pointing to an object ref: + * + * someField + * + * object + * + */ + public function testNestedMetadataArrayOfValue() + { + // set up data objects + $entityDataObjectBuilder = new EntityDataObjectBuilder(); + $parentDataObject = $entityDataObjectBuilder + ->withName("parentObject") + ->withType("parentType") + ->withLinkedEntities(['childObject1' => 'childType', 'childObject2' => 'childType']) + ->build(); + + // mock data object handler + $mockDOHInstance = AspectMock::double(DataObjectHandler::class, ["getObject" => function ($name) { + $entityDataObjectBuilder = new EntityDataObjectBuilder(); + + if ($name == "childObject1") { + return $entityDataObjectBuilder + ->withName("childObject1") + ->withType("childType") + ->withDataFields(["city" => "Hawkins", "state" => "Indiana", "zip" => "78758"]) + ->build(); + }; + + if ($name == "childObject2") { + return $entityDataObjectBuilder + ->withName("childObject2") + ->withType("childType") + ->withDataFields(["city" => "Austin", "state" => "Texas", "zip" => "78701"]) + ->build(); + } + }])->make(); + AspectMock::double(DataObjectHandler::class, ['getInstance' => $mockDOHInstance]); + + // set up metadata objects + $arrayOpElementBuilder = new OperationElementBuilder(); + $arrayElement = $arrayOpElementBuilder + ->withKey("address") + ->withType("childType") + ->withElementType(OperationDefinitionObjectHandler::ENTITY_OPERATION_ARRAY) + ->withNestedElements([]) + ->withFields([]) + ->build(); + + $parentOpElementBuilder = new OperationElementBuilder(); + $parentElement = $parentOpElementBuilder + ->withKey("parentType") + ->withType("parentType") + ->addElements(["address" => $arrayElement]) + ->build(); + + $operationDefinitionBuilder = new OperationDefinitionBuilder(); + $childOperationDefinition = $operationDefinitionBuilder + ->withName("createChildType") + ->withOperation("create") + ->withType("childType") + ->withMetadata([ + "city" => "string", + "state" => "string", + "zip" => "integer" + ])->build(); + + // mock meta data object handler + $mockDOHInstance = AspectMock::double( + OperationDefinitionObjectHandler::class, + ['getObject' => $childOperationDefinition] + )->make(); + AspectMock::double(OperationDefinitionObjectHandler::class, ['getInstance' => $mockDOHInstance]); + + // resolve data object and metadata array + $operationResolver = new OperationDataArrayResolver(); + $result = $operationResolver->resolveOperationDataArray($parentDataObject, [$parentElement], "create", false); + + // Do assert on result here + $this->assertEquals(self::NESTED_METADATA_ARRAY_RESULT, $result); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php index 00d2c7bb6..dd5b83d3b 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php @@ -5,10 +5,10 @@ */ namespace tests\unit\Magento\FunctionalTestFramework\Test\Util; +use AspectMock\Test as AspectMock; use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; use Magento\FunctionalTestingFramework\Test\Objects\ActionObject; -use Magento\FunctionalTestingFramework\Test\Objects\TestObject; use Magento\FunctionalTestingFramework\Test\Util\ActionMergeUtil; use Magento\FunctionalTestingFramework\Test\Util\ActionObjectExtractor; use PHPUnit\Framework\TestCase; @@ -121,7 +121,6 @@ public function testResolveActionStepPageData() */ public function testResolveActionStepEntityData() { - $this->markTestSkipped('This test was written using reflection instead of AspectMock. It needs refactored.'); $dataObjectName = 'myObject'; $dataObjectType = 'testObject'; $dataFieldName = 'myfield'; @@ -137,12 +136,8 @@ public function testResolveActionStepEntityData() $mockDataObject = new EntityDataObject($dataObjectName, $dataObjectType, $mockData, null, null, null); // Set up mock DataObject Handler - $mockDataHandler = $this->createMock(DataObjectHandler::class); - $mockDataHandler->expects($this->any()) - ->method('getObject') - ->with($this->matches($dataObjectName)) - ->willReturn($mockDataObject); - DataObjectHandlerReflectionUtil::setupMock($mockDataHandler); + $mockDOHInstance = AspectMock::double(DataObjectHandler::class, ['getObject' => $mockDataObject])->make(); + AspectMock::double(DataObjectHandler::class, ['getInstance' => $mockDOHInstance]); // Create test object and action object $actionAttributes = [$userInputKey => $userinputValue]; @@ -154,7 +149,5 @@ public function testResolveActionStepEntityData() $resolvedActions = $mergeUtil->resolveActionSteps($actions); $this->assertEquals($dataFieldValue, $resolvedActions[$actionName]->getCustomActionAttributes()[$userInputKey]); - - DataObjectHandlerReflectionUtil::tearDown(); } } diff --git a/dev/tests/unit/Util/DataObjectHandlerReflectionUtil.php b/dev/tests/unit/Util/DataObjectHandlerReflectionUtil.php deleted file mode 100644 index 557ab5772..000000000 --- a/dev/tests/unit/Util/DataObjectHandlerReflectionUtil.php +++ /dev/null @@ -1,47 +0,0 @@ -bindTo(null, DataObjectHandler::class); - $setMockStatic($mockObject); - } - - /** - * Sets the Data Object Handler Instance to a null value for re-initialization. - */ - public static function tearDown() - { - $resetStatic = function () { - static::$DATA_OBJECT_HANDLER = null; - }; - - $resetMockStatic = $resetStatic->bindTo(null, DataObjectHandler::class); - $resetMockStatic(); - } -} \ No newline at end of file diff --git a/dev/tests/unit/Util/EntityDataObjectBuilder.php b/dev/tests/unit/Util/EntityDataObjectBuilder.php new file mode 100644 index 000000000..fa50d1324 --- /dev/null +++ b/dev/tests/unit/Util/EntityDataObjectBuilder.php @@ -0,0 +1,117 @@ + "Hopper", + "gpa" => "3.5", + "phone" => "5555555", + "isprimary" => "true" + ]; + + /** + * Name of the data object. + * + * @var string + */ + private $name = "testDataObject"; + + /** + * Name of the data object type (e.g. customer, category etc.) + * + * @var string + */ + private $type = "testType"; + + /** + * A flat array containing linked entity name => linked entity type. + * + * @var array + */ + private $linkedEntities = []; + + /** + * An array contain references to data to be resolved by the api. + * + * @var array + */ + private $vars = []; + + /** + * A function which will build an Entity Data Object with the params specified by the object. + * + * @return EntityDataObject + */ + public function build() + { + return new EntityDataObject( + $this->name, + $this->type, + $this->data, + $this->linkedEntities, + null, + $this->vars + ); + } + + /** + * Sets the name of the EntityDataObject. + * + * @param string $name + * @return EntityDataObjectBuilder + */ + public function withName($name) + { + $this->name = $name; + return $this; + } + + /** + * Sets the type of the EntityDataObject. + * + * @param string $type + * @return EntityDataObjectBuilder + */ + public function withType($type) + { + $this->type = $type; + return $this; + } + + /** + * Sets the data fields on the object to the data field array specified in the argument. + * + * @param array $fields + * @return EntityDataObjectBuilder + */ + public function withDataFields($fields) + { + $this->data = $fields; + return $this; + } + + /** + * Sets the linked entities specified by the user as a param for Entity Data Object creation. + * + * @param array $linkedEntities + * @return EntityDataObjectBuilder + */ + public function withLinkedEntities($linkedEntities) + { + $this->linkedEntities = $linkedEntities; + return $this; + } + +} \ No newline at end of file diff --git a/dev/tests/unit/Util/ObjectHandlerReflectionUtilInterface.php b/dev/tests/unit/Util/ObjectHandlerReflectionUtilInterface.php deleted file mode 100644 index 145c1a0e3..000000000 --- a/dev/tests/unit/Util/ObjectHandlerReflectionUtilInterface.php +++ /dev/null @@ -1,24 +0,0 @@ -name, + $this->operation, + $this->type, + null, + null, + null, + null, + null, + $this->metadata, + null + ); + } + + /** + * Sets the name of the operation definition to be built. + * + * @param string $name + * @return OperationDefinitionBuilder + */ + public function withName($name) + { + $this->name = $name; + return $this; + } + + /** + * Sets the name of the operation for the object to be built. + * + * @param string $operation + * @return OperationDefinitionBuilder + */ + public function withOperation($operation) + { + $this->operation = $operation; + return $this; + } + + /** + * Sets the name of the type of operation (e.g. create, delete) + * + * @param string $type + * @return OperationDefinitionBuilder + */ + public function withType($type) + { + $this->type = $type; + return $this; + } + + /** + * Takes an array of values => type or an array of operation elements and transforms into operation metadata. + * + * @param array $metadata + * @return OperationDefinitionBuilder + */ + public function withMetadata($metadata) + { + $primitives = []; + foreach ($metadata as $fieldName => $value) { + // type check here TODO + if (is_string($value)) { + $primitives[$fieldName] = $value; + } else { + $this->metadata[] = $value; + } + } + + $this->metadata = array_merge($this->metadata, OperationElementBuilder::buildOperationElementFields($primitives)); + return $this; + } + + +} \ No newline at end of file diff --git a/dev/tests/unit/Util/OperationElementBuilder.php b/dev/tests/unit/Util/OperationElementBuilder.php new file mode 100644 index 000000000..238435c1b --- /dev/null +++ b/dev/tests/unit/Util/OperationElementBuilder.php @@ -0,0 +1,192 @@ + valueType). By default this + * value contains a set of primitive fields. + * + * @var array + */ + private $fields = [ + 'name' => 'string', + 'gpa' => 'double', + 'phone' => 'integer', + 'isPrimary' => 'boolean' + ]; + + private $nestedMetadata = []; + + /** + * The key to which the metadata defined will be mapped + * in JSON { key : value } + * + * @var string + */ + private $key = 'testType'; + + /** + * The type of value to which the metadata defined will be mapped (e.g. string, boolean, user defined object). + * in JSON { key : value } + * + * @var string + */ + private $type = 'testType'; + + /** + * The element type to which the metadata defined will be transformed into. + * in JSON: + * { } <- object + * [ ] <- array + * key : value <- field + * + * @var string + */ + private $elementType = OperationDefinitionObjectHandler::ENTITY_OPERATION_OBJECT; + + /** + * The array of elements which the Operation Element contains to resolve declarations within arrays specifically. + * Arrays can take object references or definitions within themselves. This metadata has to be at a parent level in + * order to resolve properly. + * + * @var array + */ + private $nestedElements; + + + /** + * Build function which takes params defined by the user and returns a new Operation Element. + * + * @return OperationElement + */ + public function build() + { + return new OperationElement( + $this->key, + $this->type, + $this->elementType, + null, + $this->nestedElements, + array_merge($this->nestedMetadata, self::buildOperationElementFields($this->fields)) + ); + } + + /** + * Sets a new element type, overwrites any existing. + * + * @param string $elementType + * @return OperationElementBuilder + */ + public function withElementType($elementType) + { + $this->elementType = $elementType; + return $this; + } + + /** + * Set a new set of fields or operation elements + * + * @param array $fields + * @return OperationElementBuilder + */ + public function withFields($fields) + { + $this->fields = $fields; + return $this; + } + + /** + * Sets a key for the operation element. See ref to param key for explanation. + * + * @param string $key + * @return OperationElementBuilder + */ + public function withKey($key) + { + $this->key = $key; + return $this; + } + + /** + * Sets a type for the operation element. See ref to param type for explanation. + * + * @param string $type + * @return OperationElementBuilder + */ + public function withType($type) + { + $this->type = $type; + return $this; + } + + /** + * Adds a set of new Operation Elements to the nested metadata. + * + * @param array $elementsToAdd + * @return OperationElementBuilder + */ + public function addElements($elementsToAdd) + { + foreach ($elementsToAdd as $fieldKey => $metadata) { + $this->nestedMetadata[$fieldKey] = $metadata; + } + + return $this; + } + + /** + * Adds a new set of fields (value => type) into an object parameter to be converted to Operation Elements. + * + * @param $fieldsToAdd + * @return OperationElementBuilder + */ + public function addFields($fieldsToAdd) + { + foreach ($fieldsToAdd as $fieldKey => $type) { + $this->fields[$fieldKey] = $type; + } + + return $this; + } + + /** + * Sets an array nested elements to an object property. + * + * @param array $nestedElements + * @return OperationElementBuilder + */ + public function withNestedElements($nestedElements) + { + $this->nestedElements = $nestedElements; + return $this; + } + + /** + * Takes an array of fields (value => type) and returns an array of Operations Elements of type field. + * + * @param array $fields + * @return array + */ + public static function buildOperationElementFields($fields) + { + $operationElements = []; + foreach ($fields as $fieldName => $type) { + $operationElements[] = new OperationElement( + $fieldName, + $type, + null, + OperationDefinitionObjectHandler::ENTITY_OPERATION_ENTRY + ); + } + + return $operationElements; + } +} \ No newline at end of file diff --git a/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php b/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php index 5b4f45d2a..8489a3828 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php +++ b/src/Magento/FunctionalTestingFramework/Test/Util/ActionGroupObjectExtractor.php @@ -77,7 +77,7 @@ private function extractArguments($arguments) ); foreach ($argData as $argName => $argValue) { - $parsedArguments[$argName] = $argValue[self::DEFAULT_VALUE]; + $parsedArguments[$argName] = $argValue[self::DEFAULT_VALUE] ?? null; } return $parsedArguments; From 0665f5a4d6c1e8becd5d34e360176abbebb8d1db Mon Sep 17 00:00:00 2001 From: Ian Meron Date: Mon, 20 Nov 2017 10:25:02 -0600 Subject: [PATCH 28/29] MQE-434: Create operation api unit tests - fix static code sniff failures - add static checks for unit and verification test --- bin/static-checks | 2 ++ .../Page/Objects/SectionObjectTest.php | 12 ++++++++---- .../Test/Util/ActionMergeUtilTest.php | 1 - dev/tests/unit/Util/EntityDataObjectBuilder.php | 3 +-- dev/tests/unit/Util/OperationDefinitionBuilder.php | 9 +++++---- dev/tests/unit/Util/OperationElementBuilder.php | 3 +-- .../Tests/ActionGroupMergeGenerationTest.php | 2 -- .../Tests/ReferenceReplacementGenerationTest.php | 1 - dev/tests/verification/Tests/SuiteGenerationTest.php | 1 - 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/bin/static-checks b/bin/static-checks index e1ddd268a..cdc6b8c7b 100755 --- a/bin/static-checks +++ b/bin/static-checks @@ -3,6 +3,8 @@ echo "===============================PHP CODE SNIFFER REPORT===============================" vendor/bin/phpcs ./src --standard=./dev/tests/static/Magento +vendor/bin/phpcs ./dev/tests/unit --standard=./dev/tests/static/Magento +vendor/bin/phpcs ./dev/tests/verification --standard=./dev/tests/static/Magento echo "===============================COPY PASTE DETECTOR REPORT===============================" vendor/bin/phpcpd ./src diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php index 199d2a225..6257ee0db 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Page/Objects/SectionObjectTest.php @@ -18,7 +18,8 @@ class SectionObjectTest extends TestCase /** * Assert that the section object has an element */ - public function testHasElement() { + public function testHasElement() + { $element1 = new ElementObject('element1', 'type', '#selector', null, '41', false); $element2 = new ElementObject('element2', 'type', '#selector', null, '42', true); $elements = [ @@ -32,7 +33,8 @@ public function testHasElement() { /** * Assert that the section object doesn't have an element */ - public function testDoesntHaveElement() { + public function testDoesntHaveElement() + { $element2 = new ElementObject('element2', 'type', '#selector', null, '42', true); $elements = [ 'element2' => $element2 @@ -44,7 +46,8 @@ public function testDoesntHaveElement() { /** * Assert that an element object is returned */ - public function testGetElement() { + public function testGetElement() + { $element1 = new ElementObject('element1', 'type', '#selector', null, '41', false); $element2 = new ElementObject('element2', 'type', '#selector', null, '42', true); $elements = [ @@ -60,7 +63,8 @@ public function testGetElement() { /** * Assert that null is returned if no such element */ - public function testNullGetElement() { + public function testNullGetElement() + { $element1 = new ElementObject('element1', 'type', '#selector', null, '41', false); $elements = [ 'element1' => $element1 diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php index dd5b83d3b..bbe88bf54 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ActionMergeUtilTest.php @@ -130,7 +130,6 @@ public function testResolveActionStepEntityData() $actionName = "myAction"; $actionType = "myCustomType"; - // Set up mock data object $mockData = [$dataFieldName => $dataFieldValue]; $mockDataObject = new EntityDataObject($dataObjectName, $dataObjectType, $mockData, null, null, null); diff --git a/dev/tests/unit/Util/EntityDataObjectBuilder.php b/dev/tests/unit/Util/EntityDataObjectBuilder.php index fa50d1324..ead183b8c 100644 --- a/dev/tests/unit/Util/EntityDataObjectBuilder.php +++ b/dev/tests/unit/Util/EntityDataObjectBuilder.php @@ -113,5 +113,4 @@ public function withLinkedEntities($linkedEntities) $this->linkedEntities = $linkedEntities; return $this; } - -} \ No newline at end of file +} diff --git a/dev/tests/unit/Util/OperationDefinitionBuilder.php b/dev/tests/unit/Util/OperationDefinitionBuilder.php index 516bf169c..366cb6f86 100644 --- a/dev/tests/unit/Util/OperationDefinitionBuilder.php +++ b/dev/tests/unit/Util/OperationDefinitionBuilder.php @@ -112,9 +112,10 @@ public function withMetadata($metadata) } } - $this->metadata = array_merge($this->metadata, OperationElementBuilder::buildOperationElementFields($primitives)); + $this->metadata = array_merge( + $this->metadata, + OperationElementBuilder::buildOperationElementFields($primitives) + ); return $this; } - - -} \ No newline at end of file +} diff --git a/dev/tests/unit/Util/OperationElementBuilder.php b/dev/tests/unit/Util/OperationElementBuilder.php index 238435c1b..a7a021ac2 100644 --- a/dev/tests/unit/Util/OperationElementBuilder.php +++ b/dev/tests/unit/Util/OperationElementBuilder.php @@ -61,7 +61,6 @@ class OperationElementBuilder */ private $nestedElements; - /** * Build function which takes params defined by the user and returns a new Operation Element. * @@ -189,4 +188,4 @@ public static function buildOperationElementFields($fields) return $operationElements; } -} \ No newline at end of file +} diff --git a/dev/tests/verification/Tests/ActionGroupMergeGenerationTest.php b/dev/tests/verification/Tests/ActionGroupMergeGenerationTest.php index eae2dad70..0b3f8844c 100644 --- a/dev/tests/verification/Tests/ActionGroupMergeGenerationTest.php +++ b/dev/tests/verification/Tests/ActionGroupMergeGenerationTest.php @@ -32,7 +32,6 @@ public function testActionGroupFunctionalCest() $this->runComparisonTest(self::ACTION_GROUP_FUNCTIONAL_CEST); } - /** * Generate a Cest by name and assert that it equals the corresponding .txt source of truth * @@ -51,7 +50,6 @@ private function runComparisonTest($cestName) $this->assertTrue(file_exists($cestFile)); - $this->assertFileEquals( self::RESOURCES_PATH . DIRECTORY_SEPARATOR . $cestName . ".txt", $cestFile diff --git a/dev/tests/verification/Tests/ReferenceReplacementGenerationTest.php b/dev/tests/verification/Tests/ReferenceReplacementGenerationTest.php index 572e30985..a0ee240b3 100644 --- a/dev/tests/verification/Tests/ReferenceReplacementGenerationTest.php +++ b/dev/tests/verification/Tests/ReferenceReplacementGenerationTest.php @@ -67,7 +67,6 @@ private function runComparisonTest($cestName) $this->assertTrue(file_exists($cestFile)); - $this->assertFileEquals( self::RESOURCES_PATH . DIRECTORY_SEPARATOR . $cestName . ".txt", $cestFile diff --git a/dev/tests/verification/Tests/SuiteGenerationTest.php b/dev/tests/verification/Tests/SuiteGenerationTest.php index aabd45f01..947069ad9 100644 --- a/dev/tests/verification/Tests/SuiteGenerationTest.php +++ b/dev/tests/verification/Tests/SuiteGenerationTest.php @@ -19,7 +19,6 @@ class SuiteGenerationTest extends TestCase private static $YML_EXISTS_FLAG = false; private static $TEST_GROUPS = []; - public static function setUpBeforeClass() { if (file_exists(self::CONFIG_YML_FILE)) { From 053c01f2d131a53eaf975fc2ef24a455bec32b83 Mon Sep 17 00:00:00 2001 From: Alex Kolesnyk Date: Tue, 21 Nov 2017 15:43:50 +0200 Subject: [PATCH 29/29] MQE-406: Omitting defaultValue for actionGroup argument causes error - resolve conflicts --- .../Test/Objects/ActionGroupObject.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php index 11c0f05df..40feb93de 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php +++ b/src/Magento/FunctionalTestingFramework/Test/Objects/ActionGroupObject.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\Test\Objects; +use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Test\Util\ActionMergeUtil; /** @@ -65,12 +66,23 @@ public function __construct($name, $arguments, $actions) * @param array $arguments * @param string $actionReferenceKey * @return array + * @throws TestReferenceException */ public function getSteps($arguments, $actionReferenceKey) { $mergeUtil = new ActionMergeUtil($this->name, "ActionGroup"); $args = $this->arguments; - + $emptyArguments = array_keys($args, null, true); + if (!empty($emptyArguments) && $arguments !== null) { + $diff = array_diff($emptyArguments, array_keys($arguments)); + if (!empty($diff)) { + $error = 'Argument(s) missed (' . implode(", ", $diff) . ') for actionGroup "' . $this->name . '"'; + throw new TestReferenceException($error); + } + } elseif (!empty($emptyArguments)) { + $error = 'Not enough arguments given for actionGroup "' . $this->name . '"'; + throw new TestReferenceException($error); + } if ($arguments) { $args = array_merge($args, $arguments); }