Skip to content

Commit

Permalink
Merge pull request #2 from magento-pangolin/sprint-develop
Browse files Browse the repository at this point in the history
[Pangolin] Deliver changes to mainline framework repo
  • Loading branch information
okolesnyk committed Sep 20, 2017
2 parents bd0996a + e537ce7 commit dfde8ba
Show file tree
Hide file tree
Showing 18 changed files with 417 additions and 104 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

namespace Magento\FunctionalTestingFramework\DataGenerator\Api;

use Magento\FunctionalTestingFramework\DataGenerator\Handlers\DataObjectHandler;
Expand All @@ -12,13 +13,15 @@
use Magento\FunctionalTestingFramework\DataGenerator\Objects\JsonElement;
use Magento\FunctionalTestingFramework\DataGenerator\Util\JsonObjectExtractor;
use Magento\FunctionalTestingFramework\Util\ApiClientUtil;
use Magento\Setup\Exception;

/**
* Class ApiExecutor
*/
class ApiExecutor
{
const PRIMITIVE_TYPES = ['string', 'boolean', 'integer', 'double', 'array'];
const EXCEPTION_REQUIRED_DATA = "%s of key \" %s\" in \"%s\" is required by metadata, but was not provided.";

/**
* Describes the operation for the executor ('create','update','delete')
Expand Down Expand Up @@ -149,6 +152,7 @@ private function getAuthorizationHeader($authUrl)
* @param EntityDataObject $entityObject
* @param array $jsonArrayMetadata
* @return array
* @throws \Exception
*/
private function convertJsonArray($entityObject, $jsonArrayMetadata)
{
Expand All @@ -157,8 +161,10 @@ private function convertJsonArray($entityObject, $jsonArrayMetadata)

foreach ($jsonArrayMetadata as $jsonElement) {
if ($jsonElement->getType() == JsonObjectExtractor::JSON_OBJECT_OBJ_NAME) {
$entityObj = $this->resolveJsonObjectAndEntityData($entityObject, $jsonElement->getValue());
$jsonArray[$jsonElement->getValue()] =
$this->convertJsonArray($entityObject, $jsonElement->getNestedMetadata());
$this->convertJsonArray($entityObj, $jsonElement->getNestedMetadata());
continue;
}

$jsonElementType = $jsonElement->getValue();
Expand All @@ -169,20 +175,40 @@ private function convertJsonArray($entityObject, $jsonArrayMetadata)
EntityDataObject::CEST_UNIQUE_VALUE
);

if (array_key_exists($jsonElement->getKey(), $entityObject->getUniquenessData())) {
$uniqueData = $entityObject->getUniquenessDataByName($jsonElement->getKey());
if ($uniqueData === 'suffix') {
$elementData .= (string)self::getSequence($entityObject->getName());
} else {
$elementData = (string)self::getSequence($entityObject->getName())
. $elementData;
// If data was defined at all, attempt to put it into JSON body
// If data was not defined, and element is required, throw exception
// If no data is defined, don't input defaults per primitive into JSON for the data
if ($elementData != null) {
if (array_key_exists($jsonElement->getKey(), $entityObject->getUniquenessData())) {
$uniqueData = $entityObject->getUniquenessDataByName($jsonElement->getKey());
if ($uniqueData === 'suffix') {
$elementData .= (string)self::getSequence($entityObject->getName());
} else {
$elementData = (string)self::getSequence($entityObject->getName()) . $elementData;
}
}
$jsonArray[$jsonElement->getKey()] = $this->castValue($jsonElementType, $elementData);

} elseif ($jsonElement->getRequired()) {
throw new \Exception(sprintf(
ApiExecutor::EXCEPTION_REQUIRED_DATA,
$jsonElement->getType(),
$jsonElement->getKey(),
$this->entityObject->getName()
));
}

$jsonArray[$jsonElement->getKey()] = $this->castValue($jsonElementType, $elementData);
} else {
$entityNamesOfType = $entityObject->getLinkedEntitiesOfType($jsonElementType);

// If an element is required by metadata, but was not provided in the entity, throw an exception
if ($jsonElement->getRequired() && $entityNamesOfType == null) {
throw new \Exception(sprintf(
ApiExecutor::EXCEPTION_REQUIRED_DATA,
$jsonElement->getType(),
$jsonElement->getKey(),
$this->entityObject->getName()
));
}
foreach ($entityNamesOfType as $entityName) {
$jsonDataSubArray = $this->resolveNonPrimitiveElement($entityName, $jsonElement);

Expand All @@ -198,6 +224,25 @@ private function convertJsonArray($entityObject, $jsonArrayMetadata)
return $jsonArray;
}

/**
* This function does a comparison of the entity object being matched to the json element. If there is a mismatch in
* type we attempt to use a nested entity, if the entities are properly matched, we simply return the object.
*
* @param EntityDataObject $entityObject
* @param string $jsonElementValue
* @return EntityDataObject|null
*/
private function resolveJsonObjectAndEntityData($entityObject, $jsonElementValue)
{
if ($jsonElementValue != $entityObject->getType()) {
// if we have a mismatch attempt to retrieve linked data and return just the first linkage
$linkName = $entityObject->getLinkedEntitiesOfType($jsonElementValue)[0];
return DataObjectHandler::getInstance()->getObject($linkName);
}

return $entityObject;
}

/**
* Resolves JsonObjects and pre-defined metadata (in other operation.xml file) referenced by the json metadata
*
Expand All @@ -209,8 +254,10 @@ private function resolveNonPrimitiveElement($entityName, $jsonElement)
{
$linkedEntityObj = $this->resolveLinkedEntityObject($entityName);

// in array case
if (!empty($jsonElement->getNestedJsonElement($jsonElement->getValue()))
&& $jsonElement->getType() == 'array') {
&& $jsonElement->getType() == 'array'
) {
$jsonSubArray = $this->convertJsonArray(
$linkedEntityObj,
[$jsonElement->getNestedJsonElement($jsonElement->getValue())]
Expand Down Expand Up @@ -285,6 +332,7 @@ private static function getSequence($entityName)
}

// @codingStandardsIgnoreStart

/**
* This function takes a string value and its corresponding type and returns the string cast
* into its the type passed.
Expand All @@ -304,6 +352,9 @@ private function castValue($type, $value)
$newVal = (integer)$value;
break;
case 'boolean':
if (strtolower($newVal) === 'false') {
return false;
}
$newVal = (boolean)$value;
break;
case 'double':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class JsonDefinitionObjectHandler implements ObjectHandlerInterface
const ENTITY_OPERATION_OBJECT_KEY = 'key';
const ENTITY_OPERATION_OBJECT_VALUE = 'value';
const ENTITY_OPERATION_JSON_OBJECT = 'jsonObject';
const ENTITY_OPERATION_REQUIRED = 'required';

/**
* Singleton Instance of class
Expand Down Expand Up @@ -164,7 +165,8 @@ private function initJsonDefinitions()
$jsonMetadata[] = new JsonElement(
$jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY],
$jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE],
JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY
JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY,
$jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null
);
}
}
Expand Down Expand Up @@ -192,6 +194,7 @@ private function initJsonDefinitions()
$jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_KEY],
$value,
$type,
$jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null,
$jsonSubMetadata
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,32 @@ class JsonElement
*/
private $nestedMetadata = [];

/**
* Json required attribute, used to determine if values need to be cast before insertion.
* @var bool
*/
private $required;

/**
* JsonElement constructor.
* @param string $key
* @param string $value
* @param string $type
* @param bool $required
* @param array $nestedElements
* @param array $nestedMetadata
* @param null|array $nestedMetadata
*/
public function __construct($key, $value, $type, $nestedElements = [], $nestedMetadata = null)
public function __construct($key, $value, $type, $required, $nestedElements = [], $nestedMetadata = null)
{
$this->key = $key;
$this->value = $value;
$this->type = $type;
$this->nestedElements = $nestedElements;
if ($required) {
$this->required = true;
} else {
$this->required = false;
}
$this->nestedMetadata = $nestedMetadata;
}

Expand Down Expand Up @@ -90,6 +102,16 @@ public function getType()
return $this->type;
}

/**
* Getter for required attribute
*
* @return bool
*/
public function getRequired()
{
return $this->required;
}

/**
* Returns the nested json element based on the type of entity passed
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function extractJsonObject($jsonObjectArray)
if (array_key_exists(JsonObjectExtractor::JSON_OBJECT_OBJ_NAME, $jsonObjectArray)) {
foreach ($jsonObjectArray[JsonObjectExtractor::JSON_OBJECT_OBJ_NAME] as $jsonObject) {
$nestedJsonElement = $this->extractJsonObject($jsonObject);
$nestedJsonElements[$nestedJsonElement->getKey()] = $nestedJsonElement;
$jsonMetadata[] = $nestedJsonElement;
}
}

Expand All @@ -71,6 +71,7 @@ public function extractJsonObject($jsonObjectArray)
$jsonDefKey,
$dataType,
JsonObjectExtractor::JSON_OBJECT_OBJ_NAME,
$jsonObjectArray[JsonDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null,
$nestedJsonElements,
$jsonMetadata
);
Expand All @@ -89,7 +90,8 @@ private function extractJsonEntries(&$jsonMetadata, $jsonEntryArray)
$jsonMetadata[] = new JsonElement(
$jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_KEY],
$jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY_VALUE],
JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY
JsonDefinitionObjectHandler::ENTITY_OPERATION_ENTRY,
$jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null
);
}
}
Expand Down Expand Up @@ -122,6 +124,7 @@ private function extractJsonArrays(&$jsonArrayData, $jsonArrayArray)
$jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_ARRAY_KEY],
$jsonElementValue,
JsonDefinitionObjectHandler::ENTITY_OPERATION_ARRAY,
$jsonEntryType[JsonDefinitionObjectHandler::ENTITY_OPERATION_REQUIRED] ?? null,
$nestedJsonElements
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@
</xs:choice>
<xs:attribute type="xs:string" name="key"/>
<xs:attribute type="xs:string" name="dataType" use="required"/>
<xs:attribute type="xs:boolean" name="required" use="optional"/>
</xs:complexType>
<xs:complexType name="entry">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="key" use="required"/>
<xs:attribute type="xs:string" name="type" use="optional"/>
<xs:attribute type="xs:boolean" name="required" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
Expand All @@ -47,6 +49,7 @@
</xs:choice>
<xs:attribute type="xs:string" name="key" use="required"/>
<xs:attribute type="xs:string" name="type" use="optional"/>
<xs:attribute type="xs:boolean" name="required" use="optional"/>
</xs:complexType>
<xs:complexType name="header">
<xs:simpleContent>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

namespace Magento\FunctionalTestingFramework\Exceptions;

/**
* Class TestReferenceException
*/
class TestReferenceException extends \Exception
{
/**
* TestReferenceException constructor.
* @param string $message
*/
public function __construct($message)
{
parent::__construct($message);
}
}
40 changes: 29 additions & 11 deletions src/Magento/FunctionalTestingFramework/Module/MagentoWebDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,6 @@ public function _getCurrentUri()
return Uri::retrieveUri($url);
}

/**
* Returns an array of Elements.
*
* @param string $locator
* @return array
*/
public function findElement($locator)
{
return $this->_findElements($locator);
}

/**
* Login Magento Admin with given username and password.
*
Expand Down Expand Up @@ -195,6 +184,9 @@ 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);
}

/**
Expand Down Expand Up @@ -282,6 +274,32 @@ public function scrollToTopOfPage()
$this->executeJS('window.scrollTo(0,0);');
}

/**
* Conditional click for an area that should be visible
*
* @param string $selector
* @param string dependentSelector
* @param bool $visible
*/
public function conditionalClick($selector, $dependentSelector, $visible)
{
$el = $this->_findElements($dependentSelector);
if (sizeof($el) > 1) {
throw new \Exception("more than one element matches selector " . $selector);
}

$clickCondition = null;
if ($visible) {
$clickCondition = !empty($el) && $el[0]->isDisplayed();
} else {
$clickCondition = empty($el) || !$el[0]->isDisplayed();
}

if ($clickCondition) {
$this->click($selector);
}
}

/**
* Override for _failed method in Codeception method. Adds png and html attachments to allure report
* following parent execution of test failure processing.
Expand Down
Loading

0 comments on commit dfde8ba

Please sign in to comment.