Skip to content

Commit fad2ccc

Browse files
committed
MQE-659: [ALLURE] Include the test "stepKey" in the MFTF Allure Report
1 parent 9359af2 commit fad2ccc

File tree

3 files changed

+377
-51
lines changed

3 files changed

+377
-51
lines changed

src/Magento/FunctionalTestingFramework/Allure/Adapter/MagentoAllureAdapter.php

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
use Magento\FunctionalTestingFramework\Suite\Handlers\SuiteObjectHandler;
99
use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject;
10+
use Magento\FunctionalTestingFramework\Allure\Adapter\MagentoAllureStepKeyReader;
11+
use Magento\FunctionalTestingFramework\Util\TestGenerator;
1012
use Yandex\Allure\Adapter\Model\Step;
1113
use Yandex\Allure\Codeception\AllureCodeception;
1214
use Yandex\Allure\Adapter\Event\StepStartedEvent;
@@ -17,6 +19,7 @@
1719
use Codeception\Event\FailEvent;
1820
use Codeception\Event\SuiteEvent;
1921
use Codeception\Event\StepEvent;
22+
use Codeception\Event\TestEvent;
2023

2124
/**
2225
* Class MagentoAllureAdapter
@@ -30,6 +33,23 @@
3033
class MagentoAllureAdapter extends AllureCodeception
3134
{
3235
const STEP_PASSED = "passed";
36+
const SAVE_SCREENSHOT = "save screenshot";
37+
const ALLURE_STEPKEY_FORMAT = " ------ @stepKey=";
38+
39+
/**
40+
* @var integer
41+
*/
42+
private $stepCount;
43+
44+
/**
45+
* @var array
46+
*/
47+
private $stepKeys;
48+
49+
/**
50+
* @var MagentoAllureStepKeyReader
51+
*/
52+
private $stepKeyReader;
3353

3454
/**
3555
* Array of group values passed to test runner command
@@ -179,7 +199,13 @@ public function testEnd()
179199
$formattedSteps = [];
180200
$actionGroupStepContainer = null;
181201

202+
// Get properly ordered step keys for this test
203+
$this->stepKeys = $this->stepKeyReader->getSteps($this->getPassedStepCount($rootStep));
204+
205+
$stepCount = -1;
182206
foreach ($rootStep->getSteps() as $step) {
207+
$stepCount += 1;
208+
$step->setName($this->appendStepKey($stepCount, $step->getName()));
183209
// if actionGroup flag, start nesting
184210
if (strpos($step->getName(), ActionGroupObject::ACTION_GROUP_CONTEXT_START) !== false) {
185211
$step->setName(str_replace(ActionGroupObject::ACTION_GROUP_CONTEXT_START, '', $step->getName()));
@@ -220,4 +246,58 @@ function () use ($rootStep, $formattedSteps) {
220246

221247
$this->getLifecycle()->fire(new TestCaseFinishedEvent());
222248
}
249+
250+
/**
251+
* Aggregate to parent method to prepare collecting step keys for a test
252+
*
253+
* @return void
254+
*/
255+
public function testStart(TestEvent $testEvent)
256+
{
257+
$this->stepKeys = [];
258+
$this->stepCount = 0;
259+
$this->stepKeyReader = new MagentoAllureStepKeyReader(
260+
$testEvent->getTest()->getFileName(),
261+
$testEvent->getTest()->getTestMethod()
262+
);
263+
parent::testStart($testEvent);
264+
}
265+
266+
/**
267+
* Append step key to matching step
268+
*
269+
* @param integer $stepCount
270+
* @param string $name
271+
*
272+
* @return string
273+
*/
274+
private function appendStepKey($stepCount, $name)
275+
{
276+
if (isset($this->stepKeys[$stepCount]['action']) && isset($this->stepKeys[$stepCount]['stepKey'])) {
277+
if ($this->stepKeys[$stepCount]['action'] == "comment"
278+
|| strpos($name, $this->stepKeys[$stepCount]['action']) !== false) {
279+
$name .= self::ALLURE_STEPKEY_FORMAT . $this->stepKeys[$stepCount]['stepKey'];
280+
}
281+
}
282+
return $name;
283+
}
284+
285+
/**
286+
* Return number of passed steps for a test
287+
*
288+
* @param Step $rootStep
289+
*
290+
* @return integer
291+
*/
292+
private function getPassedStepCount($rootStep)
293+
{
294+
$counter = 0;
295+
foreach ($rootStep->getSteps() as $step) {
296+
if (trim($step->getName()) == self::SAVE_SCREENSHOT) {
297+
break;
298+
}
299+
$counter += 1;
300+
}
301+
return $counter;
302+
}
223303
}
Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\FunctionalTestingFramework\Allure\Adapter;
7+
8+
use Magento\FunctionalTestingFramework\Util\TestGenerator;
9+
10+
/**
11+
* Class MagentoAllureStepKeyReader
12+
*
13+
* Parse a mftf generated Codeception php file for actions and step keys
14+
*
15+
* @package Magento\FunctionalTestingFramework\Allure
16+
*/
17+
18+
class MagentoAllureStepKeyReader
19+
{
20+
const BEFORE_MARK = "before";
21+
const AFTER_MARK = "after";
22+
const FAILED_MARK = "failed";
23+
const TEST_MARK = "test";
24+
const METHOD_BEFORE = "public function _" . self::BEFORE_MARK;
25+
const METHOD_AFTER = "public function _" . self::AFTER_MARK;
26+
const METHOD_FAILED = "public function _" . self::FAILED_MARK;
27+
const METHOD_ENDING = "\t}";
28+
const FAILED_ACTION_NAME = "saveScreenshot";
29+
const FAILED_STEP_KEY = "saveScreenshot";
30+
const REGEX_STEP_KEY = "~(?<=" . TestGenerator::STEPKEY_IN_COMMENT . ").*~";
31+
const REGEX_ACTION_NAME = "~(?<=\\". TestGenerator::ACTOR . ")([^\\(]*)(?=\()~";
32+
33+
/**
34+
* test filename
35+
*
36+
* @var string
37+
*/
38+
private $filename;
39+
40+
/**
41+
* test method name
42+
*
43+
* @var string
44+
*/
45+
private $method;
46+
47+
/**
48+
* array of lines in a file
49+
*
50+
* @var array
51+
*/
52+
private $lines;
53+
54+
/**
55+
* steps in failed
56+
*
57+
* @var array
58+
*/
59+
private $failedSteps;
60+
61+
/**
62+
* steps in _before
63+
*
64+
* @var array
65+
*/
66+
private $beforeSteps;
67+
68+
/**
69+
* steps in _after
70+
*
71+
* @var array
72+
*/
73+
private $afterSteps;
74+
75+
76+
/**
77+
* steps in test
78+
*
79+
* @var array
80+
*/
81+
private $testSteps;
82+
83+
/**
84+
* count of steps in methods
85+
*
86+
* @var array
87+
*/
88+
private $stepCount;
89+
90+
/**
91+
* MagentoAllureStepKeyReader constructor
92+
*
93+
* @param string $filename
94+
* @param string $method
95+
*/
96+
public function __construct($filename, $method)
97+
{
98+
$this->filename = $filename;
99+
$this->method = $method;
100+
$this->load();
101+
}
102+
103+
/**
104+
* Load file contents
105+
*
106+
* @return void
107+
*/
108+
private function load()
109+
{
110+
$this->lines = [];
111+
if (!file_exists($this->filename)) {
112+
return;
113+
}
114+
$lines = file($this->filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
115+
if ($lines !== false) {
116+
$this->lines = $lines;
117+
}
118+
$this->beforeSteps = $this->parseStepsForMethod(self::METHOD_BEFORE);
119+
$this->testSteps = $this->parseStepsForMethod("public function " . $this->method);
120+
$this->afterSteps = $this->parseStepsForMethod(self::METHOD_AFTER);
121+
$this->failedSteps[] = $this->parseStepsForFailed();
122+
$this->stepCount[self::BEFORE_MARK] = count($this->beforeSteps);
123+
$this->stepCount[self::AFTER_MARK] = count($this->afterSteps);
124+
$this->stepCount[self::TEST_MARK] = count($this->testSteps);
125+
$this->stepCount[self::FAILED_MARK] = count($this->failedSteps);
126+
}
127+
128+
/**
129+
* Return test step actions and step keys based on number of passed steps
130+
*
131+
* @param integer $passedCount
132+
*
133+
* @return array
134+
*/
135+
public function getSteps($passedCount)
136+
{
137+
$steps = [];
138+
$total = $this->stepCount[self::BEFORE_MARK]
139+
+ $this->stepCount[self::TEST_MARK]
140+
+ $this->stepCount[self::AFTER_MARK];
141+
if ($passedCount < 0 || $passedCount > $total) {
142+
return $steps;
143+
}
144+
145+
if ($passedCount == $total) { /* test passed */
146+
$steps = $this->beforeSteps;
147+
$steps = array_merge($steps, $this->testSteps);
148+
$steps = array_merge($steps, $this->afterSteps);
149+
} elseif ($passedCount < $this->stepCount[self::BEFORE_MARK]) { /* failed in _before() */
150+
$steps = array_slice($this->beforeSteps, 0, $passedCount);
151+
$steps = array_merge($steps, $this->failedSteps);
152+
$steps = array_merge($steps, $this->afterSteps);
153+
} elseif ($passedCount < ($this->stepCount[self::BEFORE_MARK] + $this->stepCount[self::TEST_MARK])) { /* failed in test() */
154+
$steps = $this->beforeSteps;
155+
$steps = array_merge(
156+
$steps,
157+
array_slice($this->testSteps, 0, $passedCount - $this->stepCount[self::BEFORE_MARK])
158+
);
159+
$steps = array_merge($steps, $this->failedSteps);
160+
$steps = array_merge($steps, $this->afterSteps);
161+
} else { /* failed in _after() */
162+
$steps = $this->beforeSteps;
163+
$steps = array_merge($steps, $this->testSteps);
164+
$steps = array_merge(
165+
$steps,
166+
array_slice(
167+
$this->afterSteps,
168+
0,
169+
$passedCount - $this->stepCount[self::BEFORE_MARK] - $this->stepCount[self::TEST_MARK]
170+
)
171+
);
172+
$steps = array_merge($steps, $this->failedSteps);
173+
}
174+
return $steps;
175+
}
176+
177+
/**
178+
* Parse test steps for a method
179+
*
180+
* @param string $method
181+
*
182+
* @return array
183+
*/
184+
private function parseStepsForMethod($method)
185+
{
186+
$process = false;
187+
$steps = [];
188+
foreach ($this->lines as $line) {
189+
if (!$process && strpos($line, $method) !== false) {
190+
$process = true;
191+
}
192+
if ($process && strpos($line, self::METHOD_ENDING) !== false) {
193+
$process = false;
194+
}
195+
if ($process && preg_match(self::REGEX_STEP_KEY, $line, $stepKeys)) {
196+
if (preg_match(self::REGEX_ACTION_NAME, $line, $actions)) {
197+
$steps[] = [
198+
'action' => $this->humanize($actions[0]),
199+
'stepKey' => $stepKeys[0]
200+
];
201+
}
202+
}
203+
}
204+
return $steps;
205+
}
206+
207+
/**
208+
* Parse test steps for failed method
209+
*
210+
* @return array
211+
*/
212+
private function parseStepsForFailed()
213+
{
214+
return [
215+
'action' => $this->humanize(self::FAILED_ACTION_NAME),
216+
'stepKey' => self::FAILED_STEP_KEY
217+
];
218+
}
219+
220+
/**
221+
* Convert input string into human readable words in lower case
222+
*
223+
* @param string $inStr
224+
*
225+
* @return string
226+
*/
227+
private function humanize($inStr)
228+
{
229+
$inStr = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\\1 \\2', $inStr);
230+
$inStr = preg_replace('/([a-z\d])([A-Z])/', '\\1 \\2', $inStr);
231+
$inStr = preg_replace('~\bdont\b~', 'don\'t', $inStr);
232+
return strtolower($inStr);
233+
}
234+
}

0 commit comments

Comments
 (0)