Skip to content

Commit a11f49d

Browse files
authored
MQE-293
[Customizability] Implement "parameterized" tag for page url and section element
1 parent 9ccd984 commit a11f49d

File tree

8 files changed

+194
-41
lines changed

8 files changed

+194
-41
lines changed

src/Magento/AcceptanceTestFramework/Page/Handlers/PageObjectHandler.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class PageObjectHandler implements ObjectHandlerInterface
2020
const SUB_TYPE = 'section';
2121
const URL_PATH_ATTR = 'urlPath';
2222
const MODULE_ATTR = 'module';
23+
const PARAMETERIZED = 'parameterized';
2324

2425
/**
2526
* Singleton class variable instance
@@ -97,8 +98,9 @@ private function initPageObjects()
9798
$urlPath = $pageData[PageObjectHandler::URL_PATH_ATTR];
9899
$module = $pageData[PageObjectHandler::MODULE_ATTR];
99100
$sections = array_keys($pageData[PageObjectHandler::SUB_TYPE]);
101+
$parameterized = $pageData[PageObjectHandler::PARAMETERIZED] ?? false;
100102

101-
$this->pages[$pageName] = new PageObject($pageName, $urlPath, $module, $sections);
103+
$this->pages[$pageName] = new PageObject($pageName, $urlPath, $module, $sections, $parameterized);
102104
}
103105
}
104106
}

src/Magento/AcceptanceTestFramework/Page/Handlers/SectionObjectHandler.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class SectionObjectHandler implements ObjectHandlerInterface
2222
const ELEMENT_TYPE_ATTR = 'type';
2323
const ELEMENT_LOCATOR_ATTR = 'locator';
2424
const ELEMENT_TIMEOUT_ATTR = 'timeout';
25+
const ELEMENT_PARAMETERIZED = 'parameterized';
2526

2627
/**
2728
* Singleton variable instance of class
@@ -103,12 +104,14 @@ private function initSectionObjects()
103104
$elementType = $elementData[SectionObjectHandler::ELEMENT_TYPE_ATTR];
104105
$elementLocator = $elementData[SectionObjectHandler::ELEMENT_LOCATOR_ATTR];
105106
$elementTimeout = $elementData[SectionObjectHandler::ELEMENT_TIMEOUT_ATTR] ?? null;
107+
$elementParameterized = $elementData[SectionObjectHandler::ELEMENT_PARAMETERIZED] ?? false;
106108

107109
$elements[$elementName] = new ElementObject(
108110
$elementName,
109111
$elementType,
110112
$elementLocator,
111-
$elementTimeout
113+
$elementTimeout,
114+
$elementParameterized
112115
);
113116
}
114117

src/Magento/AcceptanceTestFramework/Page/Objects/ElementObject.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,28 @@ class ElementObject
4040
*/
4141
private $timeout;
4242

43+
/**
44+
* Section element locator is parameterized
45+
*
46+
* @var bool $parameterized
47+
*/
48+
private $parameterized;
49+
4350
/**
4451
* ElementObject constructor.
4552
* @param string $name
4653
* @param string $type
4754
* @param string $locator
4855
* @param string $timeout
56+
* @param bool $parameterized
4957
*/
50-
public function __construct($name, $type, $locator, $timeout)
58+
public function __construct($name, $type, $locator, $timeout, $parameterized)
5159
{
5260
$this->name = $name;
5361
$this->type = $type;
5462
$this->locator = $locator;
5563
$this->timeout = $timeout;
64+
$this->parameterized = $parameterized;
5665
}
5766

5867
/**
@@ -98,4 +107,15 @@ public function getTimeout()
98107

99108
return (int)$this->timeout;
100109
}
110+
111+
/**
112+
* Determines if the element's selector is parameterized. Based on $parameterized property.
113+
*
114+
* @return bool
115+
*/
116+
117+
public function isParameterized()
118+
{
119+
return $this->parameterized;
120+
}
101121
}

src/Magento/AcceptanceTestFramework/Page/Objects/PageObject.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ class PageObject
3535
*/
3636
private $module;
3737

38+
/**
39+
* Page url is parameterized
40+
*
41+
* @var bool $parameterized
42+
*/
43+
private $parameterized;
44+
3845
/**
3946
* Array of page section names
4047
*
@@ -48,13 +55,15 @@ class PageObject
4855
* @param string $urlPath
4956
* @param string $module
5057
* @param array $sections
58+
* @param bool $parameterized
5159
*/
52-
public function __construct($name, $urlPath, $module, $sections)
60+
public function __construct($name, $urlPath, $module, $sections, $parameterized)
5361
{
5462
$this->name = $name;
5563
$this->url = $urlPath;
5664
$this->module = $module;
5765
$this->sectionNames = $sections;
66+
$this->parameterized = $parameterized;
5867
}
5968

6069
/**
@@ -122,4 +131,15 @@ public function getSection($sectionName)
122131

123132
return null;
124133
}
134+
135+
/**
136+
* Determines if the page's url is parameterized. Based on $parameterized property.
137+
*
138+
* @return bool
139+
*/
140+
141+
public function isParameterized()
142+
{
143+
return $this->parameterized;
144+
}
125145
}

src/Magento/AcceptanceTestFramework/Page/etc/PageObject.xsd

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,14 @@
4949
</xs:documentation>
5050
</xs:annotation>
5151
</xs:attribute>
52-
<xs:attribute type="notEmptyType" name="urlPathVariables" use="optional">
53-
<xs:annotation>
54-
<xs:documentation>
55-
Optional variable names separated by "," which are used to substitute %s in urlPath attribute.
56-
</xs:documentation>
57-
</xs:annotation>
58-
</xs:attribute>
5952
<xs:attribute type="notEmptyType" name="module" use="required">
6053
<xs:annotation>
6154
<xs:documentation>
6255
The name of the module to which the page belongs. For example: "Magento_Catalog".
6356
</xs:documentation>
6457
</xs:annotation>
6558
</xs:attribute>
59+
<xs:attribute type="xs:boolean" name="parameterized" use="optional"/>
6660
<xs:attributeGroup ref="removeAttribute"/>
6761
</xs:complexType>
6862
</xs:element>

src/Magento/AcceptanceTestFramework/Page/etc/SectionObject.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
</xs:documentation>
8080
</xs:annotation>
8181
</xs:attribute>
82+
<xs:attribute type="xs:boolean" name="parameterized" use="optional"/>
8283
<xs:attributeGroup ref="removeAttribute"/>
8384
</xs:complexType>
8485
</xs:element>

src/Magento/AcceptanceTestFramework/Test/Objects/ActionObject.php

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Magento\AcceptanceTestFramework\Page\Objects\SectionObject;
1313
use Magento\AcceptanceTestFramework\Page\Handlers\PageObjectHandler;
1414
use Magento\AcceptanceTestFramework\Page\Handlers\SectionObjectHandler;
15+
use Magento\AcceptanceTestFramework\Test\Managers\CestArrayProcessor;
1516

1617
/**
1718
* Class ActionObject
@@ -22,7 +23,9 @@ class ActionObject
2223
const MERGE_ACTION_ORDER_AFTER = 'after';
2324
const ACTION_ATTRIBUTE_URL = 'url';
2425
const ACTION_ATTRIBUTE_SELECTOR = 'selector';
26+
const ACTION_ATTRIBUTE_VARIABLE_REGEX_PARAMETER = '/\(.+\)/';
2527
const ACTION_ATTRIBUTE_VARIABLE_REGEX_PATTERN = '/{{[\w.\[\]]+}}/';
28+
const ACTION_ATTRIBUTE_VARIABLE_REGEX_NESTED = '/{{[\w.\[\]()\',${} ]+}}/';
2629

2730
/**
2831
* The unique identifier for the action
@@ -246,16 +249,39 @@ private function resolveDataInputReferences()
246249

247250
/**
248251
* Return an array containing the name (before the period) and key (after the period) in a {{reference.foo}}.
252+
* Also truncates variables inside parenthesis.
249253
*
250254
* @param string $reference
251255
* @return string[] The name and key that is referenced.
252256
*/
253257
private function stripAndSplitReference($reference)
254258
{
255259
$strippedReference = str_replace('}}', '', str_replace('{{', '', $reference));
260+
$strippedReference = preg_replace(
261+
ActionObject::ACTION_ATTRIBUTE_VARIABLE_REGEX_PARAMETER,
262+
'',
263+
$strippedReference
264+
);
256265
return explode('.', $strippedReference);
257266
}
258267

268+
/**
269+
* Returns an array containing all parameters found inside () block of test input.
270+
* Returns null if no parameters were found.
271+
*
272+
* @param string $reference
273+
* @return array|null
274+
*/
275+
private function stripAndReturnParameters($reference)
276+
{
277+
preg_match(ActionObject::ACTION_ATTRIBUTE_VARIABLE_REGEX_PARAMETER, $reference, $matches);
278+
if (!empty($matches)) {
279+
$strippedReference = str_replace(')', '', str_replace('(', '', $matches[0]));
280+
return explode(',', $strippedReference);
281+
}
282+
return null;
283+
}
284+
259285
/**
260286
* Return a string based on a reference to a page, section, or data field (e.g. {{foo.ref}} resolves to 'data')
261287
*
@@ -266,16 +292,24 @@ private function stripAndSplitReference($reference)
266292
*/
267293
private function findAndReplaceReferences($objectHandler, $inputString)
268294
{
269-
preg_match_all(ActionObject::ACTION_ATTRIBUTE_VARIABLE_REGEX_PATTERN, $inputString, $matches);
295+
//Determine if there are Parethesis and parameters. If not, use strict regex. If so, use nested regex.
296+
preg_match_all(ActionObject::ACTION_ATTRIBUTE_VARIABLE_REGEX_PATTERN, $inputString, $variableMatches);
297+
if (!empty($variableMatches[0])) {
298+
$regex = ActionObject::ACTION_ATTRIBUTE_VARIABLE_REGEX_PATTERN;
299+
} else {
300+
$regex = ActionObject::ACTION_ATTRIBUTE_VARIABLE_REGEX_NESTED;
301+
}
302+
preg_match_all($regex, $inputString, $matches);
270303

271304
if (empty($matches[0])) {
272-
return null;
305+
return $inputString;
273306
}
274307

275308
$outputString = $inputString;
276309

277310
foreach ($matches[0] as $match) {
278311
$replacement = null;
312+
$parameterized = false;
279313
list($objName) = $this->stripAndSplitReference($match);
280314

281315
$obj = $objectHandler->getObject($objName);
@@ -284,11 +318,12 @@ private function findAndReplaceReferences($objectHandler, $inputString)
284318
switch (get_class($obj)) {
285319
case PageObject::class:
286320
$replacement = $obj->getUrl();
321+
$parameterized = $obj->isParameterized();
287322
break;
288323
case SectionObject::class:
289324
list(,$objField) = $this->stripAndSplitReference($match);
325+
$parameterized = $obj->getElement($objField)->isParameterized();
290326
$replacement = $obj->getElement($objField)->getLocator();
291-
$this->timeout = $obj->getElement($objField)->getTimeout();
292327
break;
293328
case (get_class($obj) == EntityDataObject::class):
294329
list(,$objField) = $this->stripAndSplitReference($match);
@@ -315,10 +350,13 @@ private function findAndReplaceReferences($objectHandler, $inputString)
315350
throw new \Exception("Could not resolve entity reference " . $inputString);
316351
}
317352

353+
//If Page or Section's Element is has parameterized = true attribute, attempt to do parameter replacement.
354+
if ($parameterized) {
355+
$parameterList = $this->stripAndReturnParameters($match);
356+
$replacement = $this->matchParameterReferences($replacement, $parameterList);
357+
}
318358
$outputString = str_replace($match, $replacement, $outputString);
319-
320359
}
321-
322360
return $outputString;
323361
}
324362

@@ -343,4 +381,44 @@ private function resolveEntityDataUniquenessReference($reference, $entityDataObj
343381
}
344382
return $reference;
345383
}
384+
385+
/**
386+
* Finds all {{var}} occurrences in reference, and replaces them in sequence with parameters list given.
387+
* Parameter list given is also resolved, attempting to match {{data.field}} references.
388+
*
389+
* @param string $reference
390+
* @param array $parameters
391+
* @return string
392+
* @throws \Exception
393+
*/
394+
private function matchParameterReferences($reference, $parameters)
395+
{
396+
preg_match_all('/{{[\w.]+}}/', $reference, $varMatches);
397+
if (count($varMatches[0]) > count($parameters)) {
398+
throw new \Exception(
399+
"Parameter Resolution Failed: Not enough parameters given for reference " .
400+
$reference . ". Parameters Given: " . implode(",", $parameters)
401+
);
402+
} elseif (count($varMatches[0]) < count($parameters)) {
403+
throw new \Exception(
404+
"Parameter Resolution Failed: Too many parameters given for reference " .
405+
$reference . ". Parameters Given: " . implode(",", $parameters)
406+
);
407+
}
408+
409+
//Attempt to Resolve {{data}} references to actual output.
410+
$resolvedParameters = [];
411+
foreach ($parameters as $parameter) {
412+
$resolvedParameters[] = $this->findAndReplaceReferences(
413+
DataObjectHandler::getInstance(),
414+
$parameter
415+
);
416+
}
417+
418+
$resolveIndex = 0;
419+
foreach ($varMatches[0] as $var) {
420+
$reference = str_replace($var, $resolvedParameters[$resolveIndex++], $reference);
421+
}
422+
return $reference;
423+
}
346424
}

0 commit comments

Comments
 (0)