Completed
Pull Request — master (#128)
by Zac
17:42 queued 01:15
created

ToContainTextExpectation::crawlResponse()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
rs 9.4286
ccs 7
cts 7
cp 1
cc 3
eloc 6
nc 3
nop 2
crap 3
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
    private $expectationConfig;
17
    private $httpClient;
18
19 36
    public function __construct(array $expectationConfig, array $httpClientConfig = [])
20
    {
21 36
        $this->expectationConfig = $expectationConfig;
22 36
        $this->httpClient = new HttpClient($httpClientConfig);
23 36
    }
24
25 9
    public function run($actual, $expected = '')
26
    {
27 9
        if (!filter_var($actual, FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED)) {
28 1
            throw new \InvalidArgumentException('The actual value provided is not a valid URL');
29
        }
30
31 8
        $response = $this->httpClient->get(
32 8
            $actual,
33
            [
34 8
                'allow_redirects' => false,
35 8
                'http_errors' => !$this->expectationConfig['allow_errors'],
36 8
                'timeout' => $this->expectationConfig['timeout']
37 8
            ]
38 8
        );
39
40 7
        if (in_array($response->getHeader('Content-Type')[0], $this->expectationConfig['crawlable_types'])) {
41 3
            if (!$this->crawlResponse($response->getBody(), $expected)) {
42 1
                throw new Result\ExpectationFailedException(sprintf(
43 1
                    'Expected %s to contain the text "%s", but wasn\'t found in the textual content of any element',
44 1
                    $actual,
45
                    $expected
46 1
                ));
47
            }
48 6
        } elseif (!$this->findInString($response->getBody(), $expected)) {
49 2
            throw new Result\ExpectationFailedException(sprintf(
50 2
                'Expected %s to contain the text "%s", but wasn\'t found in the response',
51 2
                $actual,
52
                $expected
53 2
            ));
54
        }
55
        
56 4
        return sprintf(
57 4
            'Found the text "%s" on %s',
58 4
            $expected,
59
            $actual
60 4
        );
61
    }
62
    
63 3
    private function crawlResponse($response, $needle) {
64 3
        $crawler = new Crawler((string) $response);
65
        
66 3
        foreach ($crawler as $element) {
67 3
            if ($this->findInString($element->nodeValue, $needle)) {
68 2
                return true;
69
            }
70 1
        }
71
        
72 1
        return false;
73
    }
74
    
75 7
    private function findInString($haystack, $needle) {
76 7
        $result = @preg_match($needle, $haystack);
77
        
78 7
        if ($result === false) {
79 4
            return (strstr($haystack, $needle) !== false);
80
        } else {
81 3
            return ($result === 1);
82
        }
83
    }
84
}
85