4 * This file is part of the Behat.
5 * (c) Konstantin Kudryashov <ever.zet@gmail.com>
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
11 namespace Behat\Behat\Output\Node\EventListener\Statistics;
13 use Behat\Behat\EventDispatcher\Event\AfterStepTested;
14 use Behat\Behat\EventDispatcher\Event\BeforeFeatureTested;
15 use Behat\Behat\EventDispatcher\Event\BeforeScenarioTested;
16 use Behat\Behat\EventDispatcher\Event\FeatureTested;
17 use Behat\Behat\EventDispatcher\Event\ScenarioTested;
18 use Behat\Behat\Output\Statistics\StepStatV2;
19 use Behat\Behat\Output\Statistics\Statistics;
20 use Behat\Behat\Output\Statistics\StepStat;
21 use Behat\Behat\Tester\Exception\PendingException;
22 use Behat\Behat\Tester\Result\ExecutedStepResult;
23 use Behat\Behat\Tester\Result\StepResult;
24 use Behat\Testwork\Exception\ExceptionPresenter;
25 use Behat\Testwork\Output\Formatter;
26 use Behat\Testwork\Output\Node\EventListener\EventListener;
27 use Behat\Testwork\Tester\Result\ExceptionResult;
29 use Symfony\Component\EventDispatcher\Event;
32 * Listens and records step events to statistics.
34 * @author Konstantin Kudryashov <ever.zet@gmail.com>
36 final class StepStatsListener implements EventListener
45 private $currentFeaturePath;
47 * @var ExceptionPresenter
49 private $exceptionPresenter;
53 private $scenarioTitle;
57 private $scenarioPath;
60 * Initializes listener.
62 * @param Statistics $statistics
63 * @param ExceptionPresenter $exceptionPresenter
65 public function __construct(Statistics $statistics, ExceptionPresenter $exceptionPresenter)
67 $this->statistics = $statistics;
68 $this->exceptionPresenter = $exceptionPresenter;
74 public function listenEvent(Formatter $formatter, Event $event, $eventName)
76 $this->captureCurrentFeaturePathOnBeforeFeatureEvent($event);
77 $this->forgetCurrentFeaturePathOnAfterFeatureEvent($eventName);
78 $this->captureScenarioOnBeforeFeatureEvent($event);
79 $this->forgetScenarioOnAfterFeatureEvent($eventName);
80 $this->captureStepStatsOnAfterEvent($event);
84 * Captures current feature file path to the ivar on feature BEFORE event.
88 private function captureCurrentFeaturePathOnBeforeFeatureEvent(Event $event)
90 if (!$event instanceof BeforeFeatureTested) {
94 $this->currentFeaturePath = $event->getFeature()->getFile();
98 * Removes current feature file path from the ivar on feature AFTER event.
100 * @param string $eventName
102 private function forgetCurrentFeaturePathOnAfterFeatureEvent($eventName)
104 if (FeatureTested::AFTER !== $eventName) {
108 $this->currentFeaturePath = null;
112 * Captures current scenario title and path on scenario BEFORE event.
114 * @param Event $event
116 private function captureScenarioOnBeforeFeatureEvent(Event $event)
118 if (!$event instanceof BeforeScenarioTested) {
122 $this->scenarioTitle = sprintf('%s: %s', $event->getScenario()->getKeyword(), $event->getScenario()->getTitle());
123 $this->scenarioPath = sprintf('%s:%s', $this->currentFeaturePath, $event->getScenario()->getLine());
126 private function forgetScenarioOnAfterFeatureEvent($eventName)
128 if (ScenarioTested::AFTER !== $eventName) {
132 $this->scenarioTitle = $this->scenarioPath = null;
136 * Captures step stats on step AFTER event.
138 * @param Event $event
140 private function captureStepStatsOnAfterEvent(Event $event)
142 if (!$event instanceof AfterStepTested) {
146 $result = $event->getTestResult();
147 $step = $event->getStep();
148 $text = sprintf('%s %s', $step->getKeyword(), $step->getText());
149 $exception = $this->getStepException($result);
151 $path = $this->getStepPath($event, $exception);
152 $error = $exception ? $this->exceptionPresenter->presentException($exception) : null;
153 $stdOut = $result instanceof ExecutedStepResult ? $result->getCallResult()->getStdOut() : null;
155 $resultCode = $result->getResultCode();
156 $stat = new StepStatV2($this->scenarioTitle, $this->scenarioPath, $text, $path, $resultCode, $error, $stdOut);
158 $this->statistics->registerStepStat($stat);
162 * Gets exception from the step test results.
164 * @param StepResult $result
166 * @return null|Exception
168 private function getStepException(StepResult $result)
170 if ($result instanceof ExceptionResult) {
171 return $result->getException();
178 * Gets step path from the AFTER test event and exception.
180 * @param AfterStepTested $event
181 * @param null|Exception $exception
185 private function getStepPath(AfterStepTested $event, Exception $exception = null)
187 $path = sprintf('%s:%d', $this->currentFeaturePath, $event->getStep()->getLine());
189 if ($exception && $exception instanceof PendingException) {
190 $path = $event->getTestResult()->getStepDefinition()->getPath();