Completed
Push — master ( 247d13...46aee1 )
by Zac
13:30 queued 12s
created

ToContainTextExpectation::run()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 37
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 5

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 37
ccs 25
cts 25
cp 1
rs 8.439
cc 5
eloc 23
nc 5
nop 2
crap 5
1
<?php
2
3
namespace Overwatch\ServiceBundle\Expectation;
4
5
use GuzzleHttp\Client as HttpClient;
6
use Overwatch\ExpectationBundle\Exception as Result;
7
use Overwatch\ExpectationBundle\Expectation\ExpectationInterface;
8
use Symfony\Component\DomCrawler\Crawler;
9
10
/**
11
 * ToContainTextExpectation
12
 * Expectation that takes a plain string or regular expression. If the document
13
 * has a DOM, each element's textual content will be checked for 
14
 */
15
class ToContainTextExpectation implements ExpectationInterface
16
{
17
    private $expectationConfig;
18
    private $httpClient;
19
20 36
    public function __construct(array $expectationConfig, array $httpClientConfig = [])
21
    {
22 36
        $this->expectationConfig = $expectationConfig;
23 36
        $this->httpClient = new HttpClient($httpClientConfig);
24 36
    }
25
26 9
    public function run($actual, $expected = '')
27
    {
28 9
        if (!filter_var($actual, FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED)) {
29 1
            throw new \InvalidArgumentException('The actual value provided is not a valid URL');
30
        }
31
32 8
        $response = $this->httpClient->get(
33 8
            $actual,
34
            [
35 8
                'allow_redirects' => false,
36 8
                'http_errors'     => !$this->expectationConfig['allow_errors'],
37 8
                'timeout'         => $this->expectationConfig['timeout']
38 8
            ]
39 8
        );
40
41 7
        if (in_array($response->getHeader('Content-Type')[0], $this->expectationConfig['crawlable_types'])) {
42 3
            if (!$this->crawlResponse($response->getBody(), $expected)) {
43 1
                throw new Result\ExpectationFailedException(sprintf(
44 1
                    'Expected %s to contain the text "%s", but wasn\'t found in the textual content of any element',
45 1
                    $actual,
46
                    $expected
47 1
                ));
48
            }
49 6
        } elseif (!$this->findInString($response->getBody(), $expected)) {
50 2
            throw new Result\ExpectationFailedException(sprintf(
51 2
                'Expected %s to contain the text "%s", but wasn\'t found in the response',
52 2
                $actual,
53
                $expected
54 2
            ));
55
        }
56
        
57 4
        return sprintf(
58 4
            'Found the text "%s" on %s',
59 4
            $expected,
60
            $actual
61 4
        );
62
    }
63
    
64 3
    private function crawlResponse($response, $needle)
65
    {
66 3
        $crawler = new Crawler((string) $response);
67
        
68 3
        foreach ($crawler as $element) {
69 3
            if ($this->findInString($element->nodeValue, $needle)) {
70 2
                return true;
71
            }
72 1
        }
73
        
74 1
        return false;
75
    }
76
    
77 7
    private function findInString($haystack, $needle)
78
    {
79 7
        $result = @preg_match($needle, $haystack);
80
        
81 7
        if ($result === false) {
82 4
            return (strstr($haystack, $needle) !== false);
83
        } else {
84 3
            return ($result === 1);
85
        }
86
    }
87
}
88