Skip to content

Commit fc1630f

Browse files
committed
Merge branch 'develop' into MQE-1765
2 parents 44bd4bd + 4e7467e commit fc1630f

File tree

8 files changed

+175
-84
lines changed

8 files changed

+175
-84
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"php": "7.0.2||7.0.4||~7.0.6||~7.1.0||~7.2.0||~7.3.0",
1313
"ext-curl": "*",
1414
"allure-framework/allure-codeception": "~1.3.0",
15-
"codeception/codeception": "~2.3.4 || ~2.4.0 ",
15+
"codeception/codeception": "~2.4.5",
1616
"composer/composer": "^1.6",
1717
"consolidation/robo": "^1.0.0",
1818
"csharpru/vault-php": "~3.5.3",

composer.lock

Lines changed: 62 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dev/tests/verification/Resources/PersistenceCustomFieldsTest.txt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,5 +111,36 @@ class PersistenceCustomFieldsTestCest
111111
);
112112

113113
$I->comment("Exiting Action Group [createdAG] PersistenceActionGroup");
114+
$I->comment("Entering Action Group [AGKEY] DataPersistenceSelfReferenceActionGroup");
115+
$I->comment("[createData1AGKEY] create 'entity1' entity");
116+
PersistedObjectHandler::getInstance()->createEntity(
117+
"createData1AGKEY",
118+
"test",
119+
"entity1",
120+
[],
121+
[]
122+
);
123+
124+
$I->comment("[createData2AGKEY] create 'entity2' entity");
125+
PersistedObjectHandler::getInstance()->createEntity(
126+
"createData2AGKEY",
127+
"test",
128+
"entity2",
129+
[],
130+
[]
131+
);
132+
133+
$createData3AGKEYFields['key1'] = PersistedObjectHandler::getInstance()->retrieveEntityField('createData1AGKEY', 'field', 'test');
134+
$createData3AGKEYFields['key2'] = PersistedObjectHandler::getInstance()->retrieveEntityField('createData2AGKEY', 'field', 'test');
135+
$I->comment("[createData3AGKEY] create 'entity3' entity");
136+
PersistedObjectHandler::getInstance()->createEntity(
137+
"createData3AGKEY",
138+
"test",
139+
"entity3",
140+
[],
141+
$createData3AGKEYFields
142+
);
143+
144+
$I->comment("Exiting Action Group [AGKEY] DataPersistenceSelfReferenceActionGroup");
114145
}
115146
}

dev/tests/verification/TestModule/ActionGroup/PersistenceActionGroup.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,12 @@
3030
<getData entity="someEneity" stepKey="getData"/>
3131
<comment userInput="$createData.field$" stepKey="comment"/>
3232
</actionGroup>
33+
<actionGroup name="DataPersistenceSelfReferenceActionGroup">
34+
<createData entity="entity1" stepKey="createData1"/>
35+
<createData entity="entity2" stepKey="createData2"/>
36+
<createData entity="entity3" stepKey="createData3">
37+
<field key="key1">$createData1.field$</field>
38+
<field key="key2">$createData2.field$</field>
39+
</createData>
40+
</actionGroup>
3341
</actionGroups>

dev/tests/verification/TestModule/Test/PersistenceCustomFieldsTest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,6 @@
3333
<argument name="arg2" value="DefaultPerson.firstname"/>
3434
<argument name="arg3" value="$createdData3.firstname$"/>
3535
</actionGroup>
36+
<actionGroup ref="DataPersistenceSelfReferenceActionGroup" stepKey="AGKEY"/>
3637
</test>
3738
</tests>

src/Magento/FunctionalTestingFramework/Extension/TestContextExtension.php

Lines changed: 63 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,18 @@
1313
/**
1414
* Class TestContextExtension
1515
* @SuppressWarnings(PHPMD.UnusedPrivateField)
16+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1617
*/
1718
class TestContextExtension extends BaseExtension
1819
{
1920
const TEST_PHASE_AFTER = "_after";
20-
const CODECEPT_AFTER_VERSION = "2.3.9";
21+
const TEST_PHASE_BEFORE = "_before";
22+
2123
const TEST_FAILED_FILE = 'failed';
24+
const TEST_HOOKS = [
25+
self::TEST_PHASE_AFTER => 'AfterHook',
26+
self::TEST_PHASE_BEFORE => 'BeforeHook'
27+
];
2228

2329
/**
2430
* Codeception Events Mapping to methods
@@ -36,7 +42,6 @@ public function _initialize()
3642
{
3743
$events = [
3844
Events::TEST_START => 'testStart',
39-
Events::TEST_FAIL => 'testFail',
4045
Events::STEP_AFTER => 'afterStep',
4146
Events::TEST_END => 'testEnd',
4247
Events::RESULT_PRINT_AFTER => 'saveFailed'
@@ -57,23 +62,7 @@ public function testStart()
5762
}
5863

5964
/**
60-
* Codeception event listener function, triggered on test failure.
61-
* @param \Codeception\Event\FailEvent $e
62-
* @return void
63-
*/
64-
public function testFail(\Codeception\Event\FailEvent $e)
65-
{
66-
$cest = $e->getTest();
67-
$context = $this->extractContext($e->getFail()->getTrace(), $cest->getTestMethod());
68-
// Do not attempt to run _after if failure was in the _after block
69-
// Try to run _after but catch exceptions to prevent them from overwriting original failure.
70-
if ($context != TestContextExtension::TEST_PHASE_AFTER) {
71-
$this->runAfterBlock($e, $cest);
72-
}
73-
}
74-
75-
/**
76-
* Codeception event listener function, triggered on test ending (naturally or by error).
65+
* Codeception event listener function, triggered on test ending naturally or by errors/failures.
7766
* @param \Codeception\Event\TestEvent $e
7867
* @return void
7968
* @throws \Exception
@@ -82,55 +71,33 @@ public function testEnd(\Codeception\Event\TestEvent $e)
8271
{
8372
$cest = $e->getTest();
8473

85-
//Access private TestResultObject to find stack and if there are any errors (as opposed to failures)
74+
//Access private TestResultObject to find stack and if there are any errors/failures
8675
$testResultObject = call_user_func(\Closure::bind(
8776
function () use ($cest) {
8877
return $cest->getTestResultObject();
8978
},
9079
$cest
9180
));
92-
$errors = $testResultObject->errors();
93-
if (!empty($errors)) {
94-
foreach ($errors as $error) {
95-
if ($error->failedTest()->getTestMethod() == $cest->getName()) {
96-
$stack = $errors[0]->thrownException()->getTrace();
97-
$context = $this->extractContext($stack, $cest->getTestMethod());
98-
// Do not attempt to run _after if failure was in the _after block
99-
// Try to run _after but catch exceptions to prevent them from overwriting original failure.
100-
if ($context != TestContextExtension::TEST_PHASE_AFTER) {
101-
$this->runAfterBlock($e, $cest);
102-
}
103-
continue;
81+
82+
// check for errors in all test hooks and attach in allure
83+
if (!empty($testResultObject->errors())) {
84+
foreach ($testResultObject->errors() as $error) {
85+
if ($error->failedTest()->getTestMethod() == $cest->getTestMethod()) {
86+
$this->attachExceptionToAllure($error->thrownException(), $cest->getTestMethod());
10487
}
10588
}
10689
}
107-
// Reset Session and Cookies after all Test Runs, workaround due to functional.suite.yml restart: true
108-
$this->getDriver()->_runAfter($e->getTest());
109-
}
11090

111-
/**
112-
* Runs cest's after block, if necessary.
113-
* @param \Symfony\Component\EventDispatcher\Event $e
114-
* @param \Codeception\TestInterface $cest
115-
* @return void
116-
*/
117-
private function runAfterBlock($e, $cest)
118-
{
119-
try {
120-
$actorClass = $e->getTest()->getMetadata()->getCurrent('actor');
121-
$I = new $actorClass($cest->getScenario());
122-
if (version_compare(\Codeception\Codecept::VERSION, TestContextExtension::CODECEPT_AFTER_VERSION, "<=")) {
123-
call_user_func(\Closure::bind(
124-
function () use ($cest, $I) {
125-
$cest->executeHook($I, 'after');
126-
},
127-
null,
128-
$cest
129-
));
91+
// check for failures in all test hooks and attach in allure
92+
if (!empty($testResultObject->failures())) {
93+
foreach ($testResultObject->failures() as $failure) {
94+
if ($failure->failedTest()->getTestMethod() == $cest->getTestMethod()) {
95+
$this->attachExceptionToAllure($failure->thrownException(), $cest->getTestMethod());
96+
}
13097
}
131-
} catch (\Exception $e) {
132-
// Do not rethrow Exception
13398
}
99+
// Reset Session and Cookies after all Test Runs, workaround due to functional.suite.yml restart: true
100+
$this->getDriver()->_runAfter($e->getTest());
134101
}
135102

136103
/**
@@ -150,6 +117,46 @@ public function extractContext($trace, $class)
150117
return null;
151118
}
152119

120+
/**
121+
* Attach stack trace of exceptions thrown in each test hook to allure.
122+
* @param \Exception $exception
123+
* @param string $testMethod
124+
* @return mixed
125+
*/
126+
public function attachExceptionToAllure($exception, $testMethod)
127+
{
128+
if (is_subclass_of($exception, \PHPUnit\Framework\Exception::class)) {
129+
$trace = $exception->getSerializableTrace();
130+
} else {
131+
$trace = $exception->getTrace();
132+
}
133+
134+
$context = $this->extractContext($trace, $testMethod);
135+
136+
if (isset(self::TEST_HOOKS[$context])) {
137+
$context = self::TEST_HOOKS[$context];
138+
} else {
139+
$context = 'TestMethod';
140+
}
141+
142+
AllureHelper::addAttachmentToCurrentStep($exception, $context . 'Exception');
143+
144+
//pop suppressed exceptions and attach to allure
145+
$change = function () {
146+
if ($this instanceof \PHPUnit\Framework\ExceptionWrapper) {
147+
return $this->previous;
148+
} else {
149+
return $this->getPrevious();
150+
}
151+
};
152+
153+
$previousException = $change->call($exception);
154+
155+
if ($previousException !== null) {
156+
$this->attachExceptionToAllure($previousException, $testMethod);
157+
}
158+
}
159+
153160
/**
154161
* Codeception event listener function, triggered before step.
155162
* Check if it's a new page.

0 commit comments

Comments
 (0)