123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\Mtf\Client\Element;
- use Magento\Mtf\Client\ElementInterface;
- use Magento\Mtf\Client\Locator;
- use Magento\Mtf\ObjectManager;
- /**
- * Typified element class for conditions.
- *
- * Format value.
- * Add slash to symbols: "{", "}", "[", "]", ":".
- * 1. Single condition:
- * [Type|Param|Param|...|Param]
- * 2. List conditions:
- * [Type|Param|Param|...|Param]
- * [Type|Param|Param|...|Param]
- * [Type|Param|Param|...|Param]
- * 3. Combination condition with single condition
- * {Type|Param|Param|...|Param:[Type|Param|Param|...|Param]}
- * 4. Combination condition with list conditions
- * {Type|Param|Param|...|Param:[[Type|Param|...|Param][Type|Param|...|Param]...[Type|Param|...|Param]]}
- * 5. Top level condition
- * {TopLevelCondition:[ANY|FALSE]}{Type|Param|Param|...|Param:[[Type|Param|...|Param]...[Type|Param|...|Param]]}
- *
- * Example value:
- * {Products subselection|total amount|greater than|135|ANY:[[Price in cart|is|100][Quantity in cart|is|100]]}
- * {Conditions combination:[
- * [Subtotal|is|100]
- * {Product attribute combination|NOT FOUND|ANY:[[Attribute Set|is|Default][Attribute Set|is|Default]]}
- * ]}
- *
- * @SuppressWarnings(PHPMD.TooManyFields)
- */
- class ConditionsElement extends SimpleElement
- {
- /**
- * Count for trying fill condition element.
- */
- const TRY_COUNT = 3;
- /**
- * Main condition.
- *
- * @var string
- */
- protected $mainCondition = './/ul[contains(@id,"__1__children")]/..';
- /**
- * Identification for chooser grid.
- *
- * @var string
- */
- protected $chooserLocator = '.rule-chooser-trigger';
- /**
- * Button add condition.
- *
- * @var string
- */
- protected $addNew = './/*[contains(@class,"rule-param-new-child")]/a';
- /**
- * Button remove condition.
- *
- * @var string
- */
- protected $remove = './/*/a[@class="rule-param-remove"]';
- /**
- * New condition.
- *
- * @var string
- */
- protected $newCondition = './ul/li/span[contains(@class,"rule-param-new-child")]/..';
- /**
- * Type of new condition.
- *
- * @var string
- */
- protected $typeNew = './/*[@class="element"]/select';
- /**
- * Created condition.
- *
- * @var string
- */
- protected $created = './ul/li[span[contains(@class,"rule-param-new-child")]]/preceding-sibling::li[1]';
- /**
- * Children condition.
- *
- * @var string
- */
- protected $children = './/ul[contains(@id,"conditions__")]';
- /**
- * Parameter of condition.
- *
- * @var string
- */
- protected $param = './span[span[*[substring(@id,(string-length(@id)-%d+1))="%s"]]]';
- /**
- * Rule param wait locator.
- *
- * @var string
- */
- protected $ruleParamWait = './/*[@class="rule-param-wait"]';
- /**
- * Rule param input selector.
- *
- * @var string
- */
- protected $ruleParamInput = '[name^="rule"]';
- /**
- * Apply rule param link.
- *
- * @var string
- */
- protected $applyRuleParam = './/*[@class="rule-param-apply"]';
- /**
- * Chooser grid locator.
- *
- * @var string
- */
- protected $chooserGridLocator = 'div[id*=chooser]';
- /**
- * Datepicker xpath.
- *
- * @var string
- */
- private $datepicker = './/*[contains(@class,"ui-datepicker-trigger")]';
- /**
- * Key of last find param.
- *
- * @var int
- */
- protected $findKeyParam = 0;
- /**
- * Map of parameters.
- *
- * @var array
- */
- protected $mapParams = [
- 'attribute',
- 'operator',
- 'value_type',
- 'value',
- 'aggregator',
- ];
- /**
- * Map encode special chars.
- *
- * @var array
- */
- protected $encodeChars = [
- '\{' => '{',
- '\}' => '}',
- '\[' => '&lbracket;',
- '\]' => '&rbracket;',
- '\:' => ':',
- ];
- /**
- * Map decode special chars.
- *
- * @var array
- */
- protected $decodeChars = [
- '{' => '{',
- '}' => '}',
- '&lbracket;' => '[',
- '&rbracket;' => ']',
- ':' => ':',
- ];
- /**
- * Latest occurred exception.
- *
- * @var \Exception
- */
- protected $exception;
- /**
- * @inheritdoc
- */
- public function setValue($value)
- {
- $this->eventManager->dispatchEvent(['set_value'], [__METHOD__, $this->getAbsoluteSelector()]);
- $this->clear();
- $conditions = $this->decodeValue($value);
- $context = $this->find($this->mainCondition, Locator::SELECTOR_XPATH);
- if (!empty($conditions[0]['TopLevelCondition'])) {
- array_unshift($this->mapParams, 'aggregator');
- $condition = $this->parseTopLevelCondition($conditions[0]['TopLevelCondition']);
- $this->fillCondition($condition['rules'], $context);
- unset($conditions[0]);
- array_shift($this->mapParams);
- }
- $this->addMultipleCondition($conditions, $context);
- }
- /**
- * Add conditions combination.
- *
- * @param string $condition
- * @param ElementInterface $context
- * @return ElementInterface
- */
- protected function addConditionsCombination($condition, ElementInterface $context)
- {
- $condition = $this->parseCondition($condition);
- $this->addCondition($condition['type'], $context);
- $createdCondition = $context->find($this->created, Locator::SELECTOR_XPATH);
- $this->waitForCondition($createdCondition);
- if (!empty($condition['rules'])) {
- $this->fillCondition($condition['rules'], $createdCondition);
- }
- return $createdCondition;
- }
- /**
- * Add conditions.
- *
- * @param array $conditions
- * @param ElementInterface $context
- * @return void
- */
- protected function addMultipleCondition(array $conditions, ElementInterface $context)
- {
- foreach ($conditions as $key => $condition) {
- $elementContext = is_numeric($key) ? $context : $this->addConditionsCombination($key, $context);
- if (is_string($condition)) {
- $this->addSingleCondition($condition, $elementContext);
- } else {
- $this->addMultipleCondition($condition, $elementContext);
- }
- }
- }
- /**
- * Add single Condition.
- *
- * @param string $condition
- * @param ElementInterface $context
- * @return void
- */
- protected function addSingleCondition($condition, ElementInterface $context)
- {
- $condition = $this->parseCondition($condition);
- $this->addCondition($condition['type'], $context);
- $createdCondition = $context->find($this->created, Locator::SELECTOR_XPATH);
- $this->waitForCondition($createdCondition);
- $this->fillCondition($condition['rules'], $createdCondition);
- }
- /**
- * Click to add condition button and set type.
- *
- * @param string $type
- * @param ElementInterface $context
- * @return void
- * @throws \Exception
- */
- protected function addCondition($type, ElementInterface $context)
- {
- $newCondition = $context->find($this->newCondition, Locator::SELECTOR_XPATH);
- $count = 0;
- do {
- $newCondition->find($this->addNew, Locator::SELECTOR_XPATH)->click();
- try {
- $newCondition->find($this->typeNew, Locator::SELECTOR_XPATH, 'select')->setValue($type);
- $isSetType = true;
- } catch (\PHPUnit_Extensions_Selenium2TestCase_WebDriverException $e) {
- $isSetType = false;
- $this->exception = $e;
- $this->eventManager->dispatchEvent(['exception'], [__METHOD__, $this->getAbsoluteSelector()]);
- }
- $count++;
- } while (!$isSetType && $count < self::TRY_COUNT);
- if (!$isSetType) {
- $exception = $this->exception ? $this->exception : (new \Exception("Can not add condition: {$type}"));
- throw $exception;
- }
- }
- /**
- * Fill single condition.
- *
- * @param array $rules
- * @param ElementInterface $element
- * @return void
- * @throws \Exception
- *
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- * @SuppressWarnings(PHPMD.NPathComplexity)
- */
- protected function fillCondition(array $rules, ElementInterface $element)
- {
- $this->resetKeyParam();
- foreach ($rules as $rule) {
- /** @var ElementInterface $param */
- $param = $this->findNextParam($element);
- $isSet = false;
- $count = 0;
- do {
- try {
- $openParamLink = $param->find('a');
- if ($openParamLink->isVisible()) {
- $openParamLink->click();
- }
- $this->waitUntil(function () use ($param) {
- return $param->find($this->ruleParamInput)->isVisible() ? true : null;
- });
- if ($this->fillGrid($rule, $param)) {
- $isSet = true;
- } elseif ($this->fillSelect($rule, $param)) {
- $isSet = true;
- } elseif ($this->fillText($rule, $param)) {
- $isSet = true;
- }
- } catch (\PHPUnit_Extensions_Selenium2TestCase_WebDriverException $e) {
- $isSet = false;
- $this->exception = $e;
- $this->eventManager->dispatchEvent(['exception'], [__METHOD__, $this->getAbsoluteSelector()]);
- }
- $count++;
- } while (!$isSet && $count < self::TRY_COUNT);
- if (!$isSet) {
- $exception = $this->exception ? $this->exception : (new \Exception('Can not set value: ' . $rule));
- throw $exception;
- }
- }
- }
- /**
- * Fill grid element.
- *
- * @param string $rule
- * @param ElementInterface $param
- * @return bool
- */
- protected function fillGrid($rule, ElementInterface $param)
- {
- if (preg_match('`%(.*?)%`', $rule, $chooserGrid)) {
- $chooserConfig = explode('#', $chooserGrid[1]);
- $rule = preg_replace('`%(.*?)%`', '', $rule);
- $param->find($this->chooserLocator)->click();
- $grid = ObjectManager::getInstance()->create(
- str_replace('/', '\\', $chooserConfig[0]),
- [
- 'element' => $this->find($this->chooserGridLocator)
- ]
- );
- $grid->searchAndSelect([$chooserConfig[1] => $rule]);
- $apply = $param->find($this->applyRuleParam, Locator::SELECTOR_XPATH);
- if ($apply->isVisible()) {
- $apply->click();
- }
- return true;
- }
- return false;
- }
- /**
- * Fill select element.
- *
- * @param string $rule
- * @param ElementInterface $param
- * @return bool
- */
- protected function fillSelect($rule, ElementInterface $param)
- {
- $value = $param->find('select', Locator::SELECTOR_TAG_NAME, 'select');
- if ($value->isVisible()) {
- $value->setValue($rule);
- $this->click();
- return true;
- }
- return false;
- }
- /**
- * Fill text element.
- *
- * @param string $rule
- * @param ElementInterface $param
- * @return bool
- */
- protected function fillText($rule, ElementInterface $param)
- {
- $value = $param->find('input', Locator::SELECTOR_TAG_NAME);
- if ($value->isVisible()) {
- if (!$value->getAttribute('readonly')) {
- $value->setValue($rule);
- } else {
- $datepicker = $param->find(
- $this->datepicker,
- Locator::SELECTOR_XPATH,
- DatepickerElement::class
- );
- $datepicker->setValue($rule);
- }
- $apply = $param->find('.//*[@class="rule-param-apply"]', Locator::SELECTOR_XPATH);
- if ($apply->isVisible()) {
- $apply->click();
- }
- return true;
- }
- return false;
- }
- /**
- * Decode value.
- *
- * @param string $value
- * @return array
- * @throws \Exception
- */
- protected function decodeValue($value)
- {
- $value = str_replace(array_keys($this->encodeChars), $this->encodeChars, $value);
- $value = preg_replace('/(\]|})({|\[)/', '$1,$2', $value);
- $value = preg_replace('/{([^:]+):/', '{"$1":', $value);
- $value = preg_replace('/\[([^\[{])/', '"$1', $value);
- $value = preg_replace('/([^\]}])\]/', '$1"', $value);
- $value = str_replace(array_keys($this->decodeChars), $this->decodeChars, $value);
- $value = "[{$value}]";
- $value = json_decode($value, true);
- if (null === $value) {
- throw new \Exception('Bad format value.');
- }
- return $value;
- }
- /**
- * Parse condition.
- *
- * @param string $condition
- * @return array
- * @throws \Exception
- */
- protected function parseCondition($condition)
- {
- if (!preg_match_all('/([^|]+\|?)/', $condition, $match)) {
- throw new \Exception('Bad format condition');
- }
- foreach ($match[1] as $key => $value) {
- $match[1][$key] = rtrim($value, '|');
- }
- return [
- 'type' => array_shift($match[1]),
- 'rules' => array_values($match[1]),
- ];
- }
- /**
- * Parse top level condition.
- *
- * @param string $condition
- * @return array
- * @throws \Exception
- */
- protected function parseTopLevelCondition($condition)
- {
- if (preg_match_all('/([^|]+)\|?/', $condition, $match) === false) {
- throw new \Exception('Bad format condition');
- }
- return [
- 'rules' => $match[1],
- ];
- }
- /**
- * Find next param of condition for fill.
- *
- * @param ElementInterface $context
- * @return ElementInterface
- * @throws \Exception
- */
- protected function findNextParam(ElementInterface $context)
- {
- do {
- if (!isset($this->mapParams[$this->findKeyParam])) {
- throw new \Exception("Empty map of params");
- }
- $param = $this->mapParams[$this->findKeyParam];
- $element = $context->find(sprintf($this->param, strlen($param), $param), Locator::SELECTOR_XPATH);
- $this->findKeyParam += 1;
- } while (!$element->isVisible());
- return $element;
- }
- /**
- * Reset key of last find param.
- *
- * @return void
- */
- protected function resetKeyParam()
- {
- $this->findKeyParam = 0;
- }
- /**
- * Param wait loader.
- *
- * @param ElementInterface $element
- * @return void
- */
- protected function waitForCondition(ElementInterface $element)
- {
- $this->waitUntil(
- function () use ($element) {
- return $element->getAttribute('class') == 'rule-param-wait' ? null : true;
- }
- );
- }
- /**
- * Clear conditions.
- *
- * @return void
- */
- protected function clear()
- {
- $remote = $this->find($this->remove, Locator::SELECTOR_XPATH);
- while ($remote->isVisible()) {
- $remote->click();
- $remote = $this->find($this->remove, Locator::SELECTOR_XPATH);
- }
- }
- /**
- * Get value from conditions.
- *
- * @return null
- */
- public function getValue()
- {
- return null;
- }
- }
|