Listener   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 87
Duplicated Lines 0 %

Importance

Changes 7
Bugs 0 Features 0
Metric Value
wmc 17
eloc 35
c 7
b 0
f 0
dl 0
loc 87
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getSubscribedEvents() 0 5 1
A __construct() 0 5 1
B debugAfter() 0 28 8
A debug() 0 9 3
A hasTag() 0 15 4
1
<?php declare(strict_types=1);
2
namespace Behapi\Debug;
3
4
use Psr\Http\Message\MessageInterface;
5
use Psr\Http\Message\ResponseInterface;
6
7
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
8
9
use Behat\Testwork\Tester\Result\TestResult;
10
use Behat\Testwork\Tester\Result\TestResults;
11
use Behat\Testwork\EventDispatcher\Event\AfterTested;
12
13
use Behat\Behat\EventDispatcher\Event\ExampleTested;
14
use Behat\Behat\EventDispatcher\Event\ScenarioTested;
15
use Behat\Behat\EventDispatcher\Event\ScenarioLikeTested;
16
17
use Behat\Gherkin\Node\TaggedNodeInterface;
18
19
use Behapi\Debug\Introspection\Adapter;
20
21
use Behapi\HttpHistory\Tuple as HttpTuple;
22
use Behapi\HttpHistory\History as HttpHistory;
23
24
use function method_exists;
25
26
/**
27
 * Debug http
28
 *
29
 * Allows to debug a scenario, or, if the debug is activated, to print
30
 * a message if a scenario failed for http requests.
31
 *
32
 * @author Baptiste Clavié <[email protected]>
33
 */
34
final class Listener implements EventSubscriberInterface
35
{
36
    /** @var HttpHistory */
37
    private $history;
38
39
    /** @var Status */
40
    private $status;
41
42
    /** @var Adapter[] */
43
    private $adapters;
44
45
    /** @param Adapter[] $adapters Introspection adapters to use in this listener (sorted by priority) */
46
    public function __construct(Status $status, HttpHistory $history, array $adapters)
47
    {
48
        $this->history = $history;
49
        $this->adapters = $adapters;
50
        $this->status = $status;
51
    }
52
53
    /** {@inheritDoc} */
54
    public static function getSubscribedEvents()
55
    {
56
        return [
57
            ExampleTested::AFTER => 'debugAfter',
58
            ScenarioTested::AFTER => 'debugAfter',
59
        ];
60
    }
61
62
    public function debugAfter(ScenarioLikeTested $event): void
63
    {
64
        if (!$event instanceof AfterTested) {
65
            return;
66
        }
67
68
        // no http tag... no chocolates
69
        if (!$this->hasTag($event, 'http')) {
70
            return;
71
        }
72
73
        $result = $event->getTestResult();
74
75
        // debug only if tag is present (all debug) or only on test failures
76
        if (
77
            !$this->hasTag($event, 'debug')
78
            && (false === $this->status->isEnabled() || TestResult::FAILED !== $result->getResultCode())
79
        ) {
80
            return;
81
        }
82
83
        foreach ($this->history as $http) {
84
            $this->debug($http->getRequest());
85
86
            $response = $http->getResponse();
87
88
            if ($response instanceof ResponseInterface) {
89
                $this->debug($response);
90
            }
91
        }
92
    }
93
94
    private function debug(MessageInterface $message): void
95
    {
96
        foreach ($this->adapters as $adapter) {
97
            if (!$adapter->supports($message)) {
98
                continue;
99
            }
100
101
            $adapter->introspect($message);
102
            break;
103
        }
104
    }
105
106
    private function hasTag(ScenarioLikeTested $event, string $tag): bool
107
    {
108
        $node = $event->getNode();
109
110
        if ($node instanceof TaggedNodeInterface && $node->hasTag($tag)) {
111
            return true;
112
        }
113
114
        if (!method_exists($event, 'getFeature')) {
115
            return false;
116
        }
117
118
        $feature = $event->getFeature();
119
120
        return $feature->hasTag($tag);
121
    }
122
}
123