From aca676c0db9519284e530093ebaf71e70d9c98a4 Mon Sep 17 00:00:00 2001 From: Nikolay Geo Date: Tue, 24 Oct 2017 19:18:25 +1100 Subject: [PATCH 1/6] added logging of parameters for parametrised cest and phpunit tests --- src/Yandex/Allure/Adapter/AllureAdapter.php | 78 +++++++++++++++------ 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/src/Yandex/Allure/Adapter/AllureAdapter.php b/src/Yandex/Allure/Adapter/AllureAdapter.php index 2467ecb..e527e18 100644 --- a/src/Yandex/Allure/Adapter/AllureAdapter.php +++ b/src/Yandex/Allure/Adapter/AllureAdapter.php @@ -25,6 +25,7 @@ use Yandex\Allure\Adapter\Event\TestSuiteFinishedEvent; use Yandex\Allure\Adapter\Event\TestSuiteStartedEvent; use Yandex\Allure\Adapter\Model; +use Yandex\Allure\Adapter\Model\ParameterKind; const OUTPUT_DIRECTORY_PARAMETER = 'outputDirectory'; const DELETE_PREVIOUS_RESULTS_PARAMETER = 'deletePreviousResults'; @@ -46,7 +47,6 @@ class AllureAdapter extends Extension static $events = [ Events::SUITE_BEFORE => 'suiteBefore', Events::SUITE_AFTER => 'suiteAfter', - Events::TEST_BEFORE => 'testBefore', Events::TEST_START => 'testStart', Events::TEST_FAIL => 'testFail', Events::TEST_ERROR => 'testError', @@ -219,37 +219,37 @@ public function suiteAfter() $this->getLifecycle()->fire(new TestSuiteFinishedEvent($this->uuid)); } - public function testBefore(TestEvent $testEvent) - { - $test = $testEvent->getTest(); + private $testInvocations = array(); + private function buildTestName($test) { $testName = $test->getName(); - $event = new TestCaseStartedEvent($this->uuid, $testName); if ($test instanceof \Codeception\Test\Cest) { - $testClass = get_class($test->getTestClass()); - if (class_exists($testClass, false)) { - $annotationManager = new Annotation\AnnotationManager(Annotation\AnnotationProvider::getClassAnnotations($testClass)); - $annotationManager->updateTestCaseEvent($event); + $testFullName = get_class($test->getTestClass()) . '::' . $testName; + if(isset($this->testInvocations[$testFullName])) { + $this->testInvocations[$testFullName]++; + } else { + $this->testInvocations[$testFullName] = 0; } - } else if ($test instanceof \Codeception\Test\Cept) { - $annotations = $this->getCeptAnnotations($test); - if (count($annotations) > 0) { - $annotationManager = new Annotation\AnnotationManager($annotations); - $annotationManager->updateTestCaseEvent($event); + $currentExample = $test->getMetadata()->getCurrent(); + if ($currentExample && isset($currentExample['example']) ) { + $testName .= ' with data set #' . $this->testInvocations[$testFullName]; } } - - $this->getLifecycle()->fire($event); + return $testName; } public function testStart(TestEvent $testEvent) { $test = $testEvent->getTest(); - $testName = $test->getName(); - $event = new TestCaseStartedEvent($this->uuid, $testName); + $testName = $this->buildTestName($test); + $event = new TestCaseStartedEvent($this->uuid, $testName); if ($test instanceof \Codeception\Test\Cest) { $className = get_class($test->getTestClass()); - if (method_exists($className, $testName)){ - $annotationManager = new Annotation\AnnotationManager(Annotation\AnnotationProvider::getMethodAnnotations($className, $testName)); + if (class_exists($className, false)) { + $annotationManager = new Annotation\AnnotationManager(Annotation\AnnotationProvider::getClassAnnotations($className)); + $annotationManager->updateTestCaseEvent($event); + } + if (method_exists($className, $test->getName())){ + $annotationManager = new Annotation\AnnotationManager(Annotation\AnnotationProvider::getMethodAnnotations($className, $test->getName())); $annotationManager->updateTestCaseEvent($event); } } else if ($test instanceof \Codeception\Test\Cept) { @@ -258,9 +258,45 @@ public function testStart(TestEvent $testEvent) $annotationManager = new Annotation\AnnotationManager($annotations); $annotationManager->updateTestCaseEvent($event); } + } else if ($test instanceof \PHPUnit_Framework_TestCase) { + $methodName = $this->methodName = $test->getName(false); + $className = get_class($test); + if (class_exists($className, false)) { + $annotationManager = new Annotation\AnnotationManager( + Annotation\AnnotationProvider::getClassAnnotations($className) + ); + $annotationManager->updateTestCaseEvent($event); + } + if (method_exists($test, $methodName)) { + $annotationManager = new Annotation\AnnotationManager( + Annotation\AnnotationProvider::getMethodAnnotations(get_class($test), $methodName) + ); + $annotationManager->updateTestCaseEvent($event); + } } - $this->getLifecycle()->fire($event); + + if ($test instanceof \Codeception\Test\Cest) { + $currentExample = $test->getMetadata()->getCurrent(); + if ($currentExample && isset($currentExample['example']) ) { + foreach ($currentExample['example'] as $name => $param) { + $paramEvent = new Event\AddParameterEvent($name, $param, ParameterKind::ARGUMENT); + $this->getLifecycle()->fire($paramEvent); + } + } + } else if ($test instanceof \PHPUnit_Framework_TestCase) { + if ($test->usesDataProvider()) { + $method = new \ReflectionMethod(get_class($test), 'getProvidedData'); + $method->setAccessible(true); + $testMethod = new \ReflectionMethod(get_class($test), $test->getName(false)); + $paramNames = $testMethod->getParameters(); + foreach ($method->invoke($test) as $key => $param) { + $paramName = array_shift($paramNames); + $paramEvent = new Event\AddParameterEvent(is_null($paramName) ? $key : $paramName->getName() , $param, ParameterKind::ARGUMENT); + $this->getLifecycle()->fire($paramEvent); + } + } + } } /** From f67acf92344667ae417bf349d3238b6a2b42ef2e Mon Sep 17 00:00:00 2001 From: Nikolay Geo Date: Thu, 26 Oct 2017 12:32:59 +1100 Subject: [PATCH 2/6] fixed step parameters logging --- src/Yandex/Allure/Adapter/AllureAdapter.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Yandex/Allure/Adapter/AllureAdapter.php b/src/Yandex/Allure/Adapter/AllureAdapter.php index e527e18..8161253 100644 --- a/src/Yandex/Allure/Adapter/AllureAdapter.php +++ b/src/Yandex/Allure/Adapter/AllureAdapter.php @@ -27,6 +27,7 @@ use Yandex\Allure\Adapter\Model; use Yandex\Allure\Adapter\Model\ParameterKind; +const ARGUMENTS_LENGTH = 'arguments_length'; const OUTPUT_DIRECTORY_PARAMETER = 'outputDirectory'; const DELETE_PREVIOUS_RESULTS_PARAMETER = 'deletePreviousResults'; const IGNORED_ANNOTATION_PARAMETER = 'ignoredAnnotations'; @@ -350,8 +351,14 @@ public function testEnd() public function stepBefore(StepEvent $stepEvent) { - $stepAction = $stepEvent->getStep()->__toString(); - $this->getLifecycle()->fire(new StepStartedEvent($stepAction)); + $stepAction = $stepEvent->getStep()->getHumanizedActionWithoutArguments(); + $argumentsLength = $this->tryGetOption(ARGUMENTS_LENGTH, 200); + $stepArgs = $stepEvent->getStep()->getArgumentsAsString($argumentsLength); + $stepName = $stepAction . ' ' . $stepArgs; + + //Workaround for https://github.com/allure-framework/allure-core/issues/442 + $stepName = str_replace('.', '•', $stepName); + $this->getLifecycle()->fire(new StepStartedEvent($stepName)); } public function stepAfter() From 6fb8f3033504d27e5583cf1bc3b224ef4c8684fe Mon Sep 17 00:00:00 2001 From: Nikolay Geo Date: Thu, 26 Oct 2017 15:16:32 +1100 Subject: [PATCH 3/6] Fixed an error with not string paramters crashing xml report builder. DOMDocument::createCDATASection(string) --- src/Yandex/Allure/Adapter/AllureAdapter.php | 44 ++++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/src/Yandex/Allure/Adapter/AllureAdapter.php b/src/Yandex/Allure/Adapter/AllureAdapter.php index 8161253..48ae17a 100644 --- a/src/Yandex/Allure/Adapter/AllureAdapter.php +++ b/src/Yandex/Allure/Adapter/AllureAdapter.php @@ -281,7 +281,7 @@ public function testStart(TestEvent $testEvent) $currentExample = $test->getMetadata()->getCurrent(); if ($currentExample && isset($currentExample['example']) ) { foreach ($currentExample['example'] as $name => $param) { - $paramEvent = new Event\AddParameterEvent($name, $param, ParameterKind::ARGUMENT); + $paramEvent = new Event\AddParameterEvent($name, $this->stringifyArgument($param), ParameterKind::ARGUMENT); $this->getLifecycle()->fire($paramEvent); } } @@ -293,7 +293,7 @@ public function testStart(TestEvent $testEvent) $paramNames = $testMethod->getParameters(); foreach ($method->invoke($test) as $key => $param) { $paramName = array_shift($paramNames); - $paramEvent = new Event\AddParameterEvent(is_null($paramName) ? $key : $paramName->getName() , $param, ParameterKind::ARGUMENT); + $paramEvent = new Event\AddParameterEvent(is_null($paramName) ? $key : $paramName->getName() , $this->stringifyArgument($param), ParameterKind::ARGUMENT); $this->getLifecycle()->fire($paramEvent); } } @@ -461,4 +461,44 @@ private function splitAnnotationContent($string) return $parts; } + protected function stringifyArgument($argument) + { + if (is_string($argument)) { + return '"' . strtr($argument, ["\n" => '\n', "\r" => '\r', "\t" => ' ']) . '"'; + } elseif (is_resource($argument)) { + $argument = (string)$argument; + } elseif (is_array($argument)) { + foreach ($argument as $key => $value) { + if (is_object($value)) { + $argument[$key] = $this->getClassName($value); +} + } + } elseif (is_object($argument)) { + if (method_exists($argument, '__toString')) { + $argument = (string)$argument; + } elseif (get_class($argument) == 'Facebook\WebDriver\WebDriverBy') { + $argument = Locator::humanReadableString($argument); + } else { + $argument = $this->getClassName($argument); + } + } + + return json_encode($argument, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + } + + protected function getClassName($argument) + { + if ($argument instanceof \Closure) { + return 'Closure'; + } elseif ((isset($argument->__mocked))) { + return $this->formatClassName($argument->__mocked); + } else { + return $this->formatClassName(get_class($argument)); + } + } + + protected function formatClassName($classname) + { + return trim($classname, "\\"); + } } From 2e50e5b51ca8f05d957603a5c6ffb805fd4363be Mon Sep 17 00:00:00 2001 From: Nikolay Geo Date: Wed, 1 Nov 2017 23:30:05 +1100 Subject: [PATCH 4/6] some line brakes --- src/Yandex/Allure/Adapter/AllureAdapter.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Yandex/Allure/Adapter/AllureAdapter.php b/src/Yandex/Allure/Adapter/AllureAdapter.php index 48ae17a..99883ef 100644 --- a/src/Yandex/Allure/Adapter/AllureAdapter.php +++ b/src/Yandex/Allure/Adapter/AllureAdapter.php @@ -246,11 +246,13 @@ public function testStart(TestEvent $testEvent) if ($test instanceof \Codeception\Test\Cest) { $className = get_class($test->getTestClass()); if (class_exists($className, false)) { - $annotationManager = new Annotation\AnnotationManager(Annotation\AnnotationProvider::getClassAnnotations($className)); + $annotationManager = new Annotation\AnnotationManager( + Annotation\AnnotationProvider::getClassAnnotations($className)); $annotationManager->updateTestCaseEvent($event); } if (method_exists($className, $test->getName())){ - $annotationManager = new Annotation\AnnotationManager(Annotation\AnnotationProvider::getMethodAnnotations($className, $test->getName())); + $annotationManager = new Annotation\AnnotationManager( + Annotation\AnnotationProvider::getMethodAnnotations($className, $test->getName())); $annotationManager->updateTestCaseEvent($event); } } else if ($test instanceof \Codeception\Test\Cept) { @@ -281,7 +283,8 @@ public function testStart(TestEvent $testEvent) $currentExample = $test->getMetadata()->getCurrent(); if ($currentExample && isset($currentExample['example']) ) { foreach ($currentExample['example'] as $name => $param) { - $paramEvent = new Event\AddParameterEvent($name, $this->stringifyArgument($param), ParameterKind::ARGUMENT); + $paramEvent = new Event\AddParameterEvent( + $name, $this->stringifyArgument($param), ParameterKind::ARGUMENT); $this->getLifecycle()->fire($paramEvent); } } @@ -293,7 +296,12 @@ public function testStart(TestEvent $testEvent) $paramNames = $testMethod->getParameters(); foreach ($method->invoke($test) as $key => $param) { $paramName = array_shift($paramNames); - $paramEvent = new Event\AddParameterEvent(is_null($paramName) ? $key : $paramName->getName() , $this->stringifyArgument($param), ParameterKind::ARGUMENT); + $paramEvent = new Event\AddParameterEvent( + is_null($paramName) + ? $key + : $paramName->getName(), + $this->stringifyArgument($param), + ParameterKind::ARGUMENT); $this->getLifecycle()->fire($paramEvent); } } From d0f75d07b3da61a7425738b52045ce2635e5e454 Mon Sep 17 00:00:00 2001 From: Nikolay Geo Date: Sun, 5 Nov 2017 00:01:47 +1100 Subject: [PATCH 5/6] Better naming of Gherkin tests (with scenario title and parameter values) --- src/Yandex/Allure/Adapter/AllureAdapter.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Yandex/Allure/Adapter/AllureAdapter.php b/src/Yandex/Allure/Adapter/AllureAdapter.php index 99883ef..433ad35 100644 --- a/src/Yandex/Allure/Adapter/AllureAdapter.php +++ b/src/Yandex/Allure/Adapter/AllureAdapter.php @@ -199,7 +199,7 @@ private function prepareOutputDirectory( $filesystem->remove($files); } } - + public function suiteBefore(SuiteEvent $suiteEvent) { $suite = $suiteEvent->getSuite(); @@ -234,10 +234,12 @@ private function buildTestName($test) { if ($currentExample && isset($currentExample['example']) ) { $testName .= ' with data set #' . $this->testInvocations[$testFullName]; } + } else if($test instanceof \Codeception\Test\Gherkin) { + $testName = $test->getMetadata()->getFeature(); } return $testName; } - + public function testStart(TestEvent $testEvent) { $test = $testEvent->getTest(); From 4edc54e8da679f2544d4cae291bff827bbd65cf9 Mon Sep 17 00:00:00 2001 From: Nikolay Geo Date: Sun, 5 Nov 2017 11:43:54 +1100 Subject: [PATCH 6/6] Better resolution of Gherkin steps (autoextract step names from metastpes) --- src/Yandex/Allure/Adapter/AllureAdapter.php | 67 +++++++++++++++------ 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/src/Yandex/Allure/Adapter/AllureAdapter.php b/src/Yandex/Allure/Adapter/AllureAdapter.php index 433ad35..37703e8 100644 --- a/src/Yandex/Allure/Adapter/AllureAdapter.php +++ b/src/Yandex/Allure/Adapter/AllureAdapter.php @@ -1,19 +1,27 @@ getName(); - if ($test instanceof \Codeception\Test\Cest) { + if ($test instanceof Cest) { $testFullName = get_class($test->getTestClass()) . '::' . $testName; if(isset($this->testInvocations[$testFullName])) { $this->testInvocations[$testFullName]++; @@ -234,7 +245,7 @@ private function buildTestName($test) { if ($currentExample && isset($currentExample['example']) ) { $testName .= ' with data set #' . $this->testInvocations[$testFullName]; } - } else if($test instanceof \Codeception\Test\Gherkin) { + } else if($test instanceof Gherkin) { $testName = $test->getMetadata()->getFeature(); } return $testName; @@ -245,7 +256,7 @@ public function testStart(TestEvent $testEvent) $test = $testEvent->getTest(); $testName = $this->buildTestName($test); $event = new TestCaseStartedEvent($this->uuid, $testName); - if ($test instanceof \Codeception\Test\Cest) { + if ($test instanceof Cest) { $className = get_class($test->getTestClass()); if (class_exists($className, false)) { $annotationManager = new Annotation\AnnotationManager( @@ -257,7 +268,18 @@ public function testStart(TestEvent $testEvent) Annotation\AnnotationProvider::getMethodAnnotations($className, $test->getName())); $annotationManager->updateTestCaseEvent($event); } - } else if ($test instanceof \Codeception\Test\Cept) { + } else if ($test instanceof Gherkin) { + $featureTags = $test->getFeatureNode()->getTags(); + $scenarioTags = $test->getScenarioNode()->getTags(); + $event->setLabels( + array_map( + function ($a) { + return new Label($a, LabelType::FEATURE); + }, + array_merge($featureTags, $scenarioTags) + ) + ); + } else if ($test instanceof Cept) { $annotations = $this->getCeptAnnotations($test); if (count($annotations) > 0) { $annotationManager = new Annotation\AnnotationManager($annotations); @@ -281,7 +303,7 @@ public function testStart(TestEvent $testEvent) } $this->getLifecycle()->fire($event); - if ($test instanceof \Codeception\Test\Cest) { + if ($test instanceof Cest) { $currentExample = $test->getMetadata()->getCurrent(); if ($currentExample && isset($currentExample['example']) ) { foreach ($currentExample['example'] as $name => $param) { @@ -361,15 +383,24 @@ public function testEnd() public function stepBefore(StepEvent $stepEvent) { - $stepAction = $stepEvent->getStep()->getHumanizedActionWithoutArguments(); $argumentsLength = $this->tryGetOption(ARGUMENTS_LENGTH, 200); + + $stepAction = $stepEvent->getStep()->getHumanizedActionWithoutArguments(); $stepArgs = $stepEvent->getStep()->getArgumentsAsString($argumentsLength); + + if (!trim($stepAction)) { + $stepAction = $stepEvent->getStep()->getMetaStep()->getHumanizedActionWithoutArguments(); + $stepArgs = $stepEvent->getStep()->getMetaStep()->getArgumentsAsString($argumentsLength); + } + $stepName = $stepAction . ' ' . $stepArgs; //Workaround for https://github.com/allure-framework/allure-core/issues/442 $stepName = str_replace('.', '•', $stepName); + + $this->emptyStep = false; $this->getLifecycle()->fire(new StepStartedEvent($stepName)); - } +} public function stepAfter() { @@ -414,38 +445,38 @@ private function getCeptAnnotations($test) $output = []; if (preg_match('/\*\s\@(.*)\((.*)\)/', $line, $output) > 0) { if ($output[1] == "Features") { - $feature = new \Yandex\Allure\Adapter\Annotation\Features(); + $feature = new Features(); $features = $this->splitAnnotationContent($output[2]); foreach($features as $featureName) { $feature->featureNames[] = $featureName; } $annotations[get_class($feature)] = $feature; } else if ($output[1] == 'Title') { - $title = new \Yandex\Allure\Adapter\Annotation\Title(); + $title = new Title(); $title_content = str_replace('"', '', $output[2]); $title->value = $title_content; $annotations[get_class($title)] = $title; } else if ($output[1] == 'Description') { - $description = new \Yandex\Allure\Adapter\Annotation\Description(); + $description = new Description(); $description_content = str_replace('"', '', $output[2]); $description->value = $description_content; $annotations[get_class($description)] = $description; } else if ($output[1] == 'Stories') { $stories = $this->splitAnnotationContent($output[2]); - $story = new \Yandex\Allure\Adapter\Annotation\Stories(); + $story = new Stories(); foreach($stories as $storyName) { $story->stories[] = $storyName; } $annotations[get_class($story)] = $story; } else if ($output[1] == 'Issues') { $issues = $this->splitAnnotationContent($output[2]); - $issue = new \Yandex\Allure\Adapter\Annotation\Issues(); + $issue = new Issues(); foreach($issues as $issueName) { $issue->issueKeys[] = $issueName; } $annotations[get_class($issue)] = $issue; } else { - \Codeception\Util\Debug::debug("Tag not detected: ".$output[1]); + Debug::debug("Tag not detected: ".$output[1]); } } }