Skip to content

[Pangolin] Deliver changes to mainline framework repo #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Sep 20, 2017
Merged
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