0f0e6fa71b93ef0a20b967fcb1cb9221b488e044
[yaffs-website] / vendor / behat / mink / src / WebAssert.php
1 <?php
2
3 /*
4  * This file is part of the Mink package.
5  * (c) Konstantin Kudryashov <ever.zet@gmail.com>
6  *
7  * For the full copyright and license information, please view the LICENSE
8  * file that was distributed with this source code.
9  */
10
11 namespace Behat\Mink;
12
13 use Behat\Mink\Element\Element;
14 use Behat\Mink\Element\ElementInterface;
15 use Behat\Mink\Element\NodeElement;
16 use Behat\Mink\Element\TraversableElement;
17 use Behat\Mink\Exception\ElementNotFoundException;
18 use Behat\Mink\Exception\ExpectationException;
19 use Behat\Mink\Exception\ResponseTextException;
20 use Behat\Mink\Exception\ElementHtmlException;
21 use Behat\Mink\Exception\ElementTextException;
22
23 /**
24  * Mink web assertions tool.
25  *
26  * @author Konstantin Kudryashov <ever.zet@gmail.com>
27  */
28 class WebAssert
29 {
30     protected $session;
31
32     /**
33      * Initializes assertion engine.
34      *
35      * @param Session $session
36      */
37     public function __construct(Session $session)
38     {
39         $this->session = $session;
40     }
41
42     /**
43      * Checks that current session address is equals to provided one.
44      *
45      * @param string $page
46      *
47      * @throws ExpectationException
48      */
49     public function addressEquals($page)
50     {
51         $expected = $this->cleanUrl($page);
52         $actual = $this->getCurrentUrlPath();
53
54         $this->assert($actual === $expected, sprintf('Current page is "%s", but "%s" expected.', $actual, $expected));
55     }
56
57     /**
58      * Checks that current session address is not equals to provided one.
59      *
60      * @param string $page
61      *
62      * @throws ExpectationException
63      */
64     public function addressNotEquals($page)
65     {
66         $expected = $this->cleanUrl($page);
67         $actual = $this->getCurrentUrlPath();
68
69         $this->assert($actual !== $expected, sprintf('Current page is "%s", but should not be.', $actual));
70     }
71
72     /**
73      * Checks that current session address matches regex.
74      *
75      * @param string $regex
76      *
77      * @throws ExpectationException
78      */
79     public function addressMatches($regex)
80     {
81         $actual = $this->getCurrentUrlPath();
82         $message = sprintf('Current page "%s" does not match the regex "%s".', $actual, $regex);
83
84         $this->assert((bool) preg_match($regex, $actual), $message);
85     }
86
87     /**
88      * Checks that specified cookie exists and its value equals to a given one.
89      *
90      * @param string $name  cookie name
91      * @param string $value cookie value
92      *
93      * @throws ExpectationException
94      */
95     public function cookieEquals($name, $value)
96     {
97         $this->cookieExists($name);
98
99         $actualValue = $this->session->getCookie($name);
100         $message = sprintf('Cookie "%s" value is "%s", but should be "%s".', $name, $actualValue, $value);
101
102         $this->assert($actualValue == $value, $message);
103     }
104
105     /**
106      * Checks that specified cookie exists.
107      *
108      * @param string $name cookie name
109      *
110      * @throws ExpectationException
111      */
112     public function cookieExists($name)
113     {
114         $message = sprintf('Cookie "%s" is not set, but should be.', $name);
115         $this->assert($this->session->getCookie($name) !== null, $message);
116     }
117
118     /**
119      * Checks that current response code equals to provided one.
120      *
121      * @param int $code
122      *
123      * @throws ExpectationException
124      */
125     public function statusCodeEquals($code)
126     {
127         $actual = $this->session->getStatusCode();
128         $message = sprintf('Current response status code is %d, but %d expected.', $actual, $code);
129
130         $this->assert(intval($code) === intval($actual), $message);
131     }
132
133     /**
134      * Checks that current response code not equals to provided one.
135      *
136      * @param int $code
137      *
138      * @throws ExpectationException
139      */
140     public function statusCodeNotEquals($code)
141     {
142         $actual = $this->session->getStatusCode();
143         $message = sprintf('Current response status code is %d, but should not be.', $actual);
144
145         $this->assert(intval($code) !== intval($actual), $message);
146     }
147
148     /**
149      * Checks that current response header equals value.
150      *
151      * @param string $name
152      * @param string $value
153      *
154      * @throws ExpectationException
155      */
156     public function responseHeaderEquals($name, $value)
157     {
158         $actual = $this->session->getResponseHeader($name);
159         $message = sprintf('Current response header "%s" is "%s", but "%s" expected.', $name, $actual, $value);
160
161         $this->assert($value === $actual, $message);
162     }
163
164     /**
165      * Checks that current response header does not equal value.
166      *
167      * @param string $name
168      * @param string $value
169      *
170      * @throws ExpectationException
171      */
172     public function responseHeaderNotEquals($name, $value)
173     {
174         $actual = $this->session->getResponseHeader($name);
175         $message = sprintf('Current response header "%s" is "%s", but should not be.', $name, $actual, $value);
176
177         $this->assert($value !== $actual, $message);
178     }
179
180     /**
181      * Checks that current response header contains value.
182      *
183      * @param string $name
184      * @param string $value
185      *
186      * @throws ExpectationException
187      */
188     public function responseHeaderContains($name, $value)
189     {
190         $actual = $this->session->getResponseHeader($name);
191         $message = sprintf('The text "%s" was not found anywhere in the "%s" response header.', $value, $name);
192
193         $this->assert(false !== stripos($actual, $value), $message);
194     }
195
196     /**
197      * Checks that current response header does not contain value.
198      *
199      * @param string $name
200      * @param string $value
201      *
202      * @throws ExpectationException
203      */
204     public function responseHeaderNotContains($name, $value)
205     {
206         $actual = $this->session->getResponseHeader($name);
207         $message = sprintf('The text "%s" was found in the "%s" response header, but it should not.', $value, $name);
208
209         $this->assert(false === stripos($actual, $value), $message);
210     }
211
212     /**
213      * Checks that current response header matches regex.
214      *
215      * @param string $name
216      * @param string $regex
217      *
218      * @throws ExpectationException
219      */
220     public function responseHeaderMatches($name, $regex)
221     {
222         $actual = $this->session->getResponseHeader($name);
223         $message = sprintf('The pattern "%s" was not found anywhere in the "%s" response header.', $regex, $name);
224
225         $this->assert((bool) preg_match($regex, $actual), $message);
226     }
227
228     /**
229      * Checks that current response header does not match regex.
230      *
231      * @param string $name
232      * @param string $regex
233      *
234      * @throws ExpectationException
235      */
236     public function responseHeaderNotMatches($name, $regex)
237     {
238         $actual = $this->session->getResponseHeader($name);
239         $message = sprintf(
240             'The pattern "%s" was found in the text of the "%s" response header, but it should not.',
241             $regex,
242             $name
243         );
244
245         $this->assert(!preg_match($regex, $actual), $message);
246     }
247
248     /**
249      * Checks that current page contains text.
250      *
251      * @param string $text
252      *
253      * @throws ResponseTextException
254      */
255     public function pageTextContains($text)
256     {
257         $actual = $this->session->getPage()->getText();
258         $actual = preg_replace('/\s+/u', ' ', $actual);
259         $regex = '/'.preg_quote($text, '/').'/ui';
260         $message = sprintf('The text "%s" was not found anywhere in the text of the current page.', $text);
261
262         $this->assertResponseText((bool) preg_match($regex, $actual), $message);
263     }
264
265     /**
266      * Checks that current page does not contains text.
267      *
268      * @param string $text
269      *
270      * @throws ResponseTextException
271      */
272     public function pageTextNotContains($text)
273     {
274         $actual = $this->session->getPage()->getText();
275         $actual = preg_replace('/\s+/u', ' ', $actual);
276         $regex = '/'.preg_quote($text, '/').'/ui';
277         $message = sprintf('The text "%s" appears in the text of this page, but it should not.', $text);
278
279         $this->assertResponseText(!preg_match($regex, $actual), $message);
280     }
281
282     /**
283      * Checks that current page text matches regex.
284      *
285      * @param string $regex
286      *
287      * @throws ResponseTextException
288      */
289     public function pageTextMatches($regex)
290     {
291         $actual = $this->session->getPage()->getText();
292         $message = sprintf('The pattern %s was not found anywhere in the text of the current page.', $regex);
293
294         $this->assertResponseText((bool) preg_match($regex, $actual), $message);
295     }
296
297     /**
298      * Checks that current page text does not matches regex.
299      *
300      * @param string $regex
301      *
302      * @throws ResponseTextException
303      */
304     public function pageTextNotMatches($regex)
305     {
306         $actual = $this->session->getPage()->getText();
307         $message = sprintf('The pattern %s was found in the text of the current page, but it should not.', $regex);
308
309         $this->assertResponseText(!preg_match($regex, $actual), $message);
310     }
311
312     /**
313      * Checks that page HTML (response content) contains text.
314      *
315      * @param string $text
316      *
317      * @throws ExpectationException
318      */
319     public function responseContains($text)
320     {
321         $actual = $this->session->getPage()->getContent();
322         $regex = '/'.preg_quote($text, '/').'/ui';
323         $message = sprintf('The string "%s" was not found anywhere in the HTML response of the current page.', $text);
324
325         $this->assert((bool) preg_match($regex, $actual), $message);
326     }
327
328     /**
329      * Checks that page HTML (response content) does not contains text.
330      *
331      * @param string $text
332      *
333      * @throws ExpectationException
334      */
335     public function responseNotContains($text)
336     {
337         $actual = $this->session->getPage()->getContent();
338         $regex = '/'.preg_quote($text, '/').'/ui';
339         $message = sprintf('The string "%s" appears in the HTML response of this page, but it should not.', $text);
340
341         $this->assert(!preg_match($regex, $actual), $message);
342     }
343
344     /**
345      * Checks that page HTML (response content) matches regex.
346      *
347      * @param string $regex
348      *
349      * @throws ExpectationException
350      */
351     public function responseMatches($regex)
352     {
353         $actual = $this->session->getPage()->getContent();
354         $message = sprintf('The pattern %s was not found anywhere in the HTML response of the page.', $regex);
355
356         $this->assert((bool) preg_match($regex, $actual), $message);
357     }
358
359     /**
360      * Checks that page HTML (response content) does not matches regex.
361      *
362      * @param $regex
363      *
364      * @throws ExpectationException
365      */
366     public function responseNotMatches($regex)
367     {
368         $actual = $this->session->getPage()->getContent();
369         $message = sprintf('The pattern %s was found in the HTML response of the page, but it should not.', $regex);
370
371         $this->assert(!preg_match($regex, $actual), $message);
372     }
373
374     /**
375      * Checks that there is specified number of specific elements on the page.
376      *
377      * @param string           $selectorType element selector type (css, xpath)
378      * @param string|array     $selector     element selector
379      * @param int              $count        expected count
380      * @param ElementInterface $container    document to check against
381      *
382      * @throws ExpectationException
383      */
384     public function elementsCount($selectorType, $selector, $count, ElementInterface $container = null)
385     {
386         $container = $container ?: $this->session->getPage();
387         $nodes = $container->findAll($selectorType, $selector);
388
389         $message = sprintf(
390             '%d %s found on the page, but should be %d.',
391             count($nodes),
392             $this->getMatchingElementRepresentation($selectorType, $selector, count($nodes) !== 1),
393             $count
394         );
395
396         $this->assert(intval($count) === count($nodes), $message);
397     }
398
399     /**
400      * Checks that specific element exists on the current page.
401      *
402      * @param string           $selectorType element selector type (css, xpath)
403      * @param string|array     $selector     element selector
404      * @param ElementInterface $container    document to check against
405      *
406      * @return NodeElement
407      *
408      * @throws ElementNotFoundException
409      */
410     public function elementExists($selectorType, $selector, ElementInterface $container = null)
411     {
412         $container = $container ?: $this->session->getPage();
413         $node = $container->find($selectorType, $selector);
414
415         if (null === $node) {
416             if (is_array($selector)) {
417                 $selector = implode(' ', $selector);
418             }
419
420             throw new ElementNotFoundException($this->session->getDriver(), 'element', $selectorType, $selector);
421         }
422
423         return $node;
424     }
425
426     /**
427      * Checks that specific element does not exists on the current page.
428      *
429      * @param string           $selectorType element selector type (css, xpath)
430      * @param string|array     $selector     element selector
431      * @param ElementInterface $container    document to check against
432      *
433      * @throws ExpectationException
434      */
435     public function elementNotExists($selectorType, $selector, ElementInterface $container = null)
436     {
437         $container = $container ?: $this->session->getPage();
438         $node = $container->find($selectorType, $selector);
439
440         $message = sprintf(
441             'An %s appears on this page, but it should not.',
442             $this->getMatchingElementRepresentation($selectorType, $selector)
443         );
444
445         $this->assert(null === $node, $message);
446     }
447
448     /**
449      * Checks that specific element contains text.
450      *
451      * @param string       $selectorType element selector type (css, xpath)
452      * @param string|array $selector     element selector
453      * @param string       $text         expected text
454      *
455      * @throws ElementTextException
456      */
457     public function elementTextContains($selectorType, $selector, $text)
458     {
459         $element = $this->elementExists($selectorType, $selector);
460         $actual = $element->getText();
461         $regex = '/'.preg_quote($text, '/').'/ui';
462
463         $message = sprintf(
464             'The text "%s" was not found in the text of the %s.',
465             $text,
466             $this->getMatchingElementRepresentation($selectorType, $selector)
467         );
468
469         $this->assertElementText((bool) preg_match($regex, $actual), $message, $element);
470     }
471
472     /**
473      * Checks that specific element does not contains text.
474      *
475      * @param string       $selectorType element selector type (css, xpath)
476      * @param string|array $selector     element selector
477      * @param string       $text         expected text
478      *
479      * @throws ElementTextException
480      */
481     public function elementTextNotContains($selectorType, $selector, $text)
482     {
483         $element = $this->elementExists($selectorType, $selector);
484         $actual = $element->getText();
485         $regex = '/'.preg_quote($text, '/').'/ui';
486
487         $message = sprintf(
488             'The text "%s" appears in the text of the %s, but it should not.',
489             $text,
490             $this->getMatchingElementRepresentation($selectorType, $selector)
491         );
492
493         $this->assertElementText(!preg_match($regex, $actual), $message, $element);
494     }
495
496     /**
497      * Checks that specific element contains HTML.
498      *
499      * @param string       $selectorType element selector type (css, xpath)
500      * @param string|array $selector     element selector
501      * @param string       $html         expected text
502      *
503      * @throws ElementHtmlException
504      */
505     public function elementContains($selectorType, $selector, $html)
506     {
507         $element = $this->elementExists($selectorType, $selector);
508         $actual = $element->getHtml();
509         $regex = '/'.preg_quote($html, '/').'/ui';
510
511         $message = sprintf(
512             'The string "%s" was not found in the HTML of the %s.',
513             $html,
514             $this->getMatchingElementRepresentation($selectorType, $selector)
515         );
516
517         $this->assertElement((bool) preg_match($regex, $actual), $message, $element);
518     }
519
520     /**
521      * Checks that specific element does not contains HTML.
522      *
523      * @param string       $selectorType element selector type (css, xpath)
524      * @param string|array $selector     element selector
525      * @param string       $html         expected text
526      *
527      * @throws ElementHtmlException
528      */
529     public function elementNotContains($selectorType, $selector, $html)
530     {
531         $element = $this->elementExists($selectorType, $selector);
532         $actual = $element->getHtml();
533         $regex = '/'.preg_quote($html, '/').'/ui';
534
535         $message = sprintf(
536             'The string "%s" appears in the HTML of the %s, but it should not.',
537             $html,
538             $this->getMatchingElementRepresentation($selectorType, $selector)
539         );
540
541         $this->assertElement(!preg_match($regex, $actual), $message, $element);
542     }
543
544     /**
545      * Checks that an attribute exists in an element.
546      *
547      * @param string       $selectorType
548      * @param string|array $selector
549      * @param string       $attribute
550      *
551      * @return NodeElement
552      *
553      * @throws ElementHtmlException
554      */
555     public function elementAttributeExists($selectorType, $selector, $attribute)
556     {
557         $element = $this->elementExists($selectorType, $selector);
558
559         $message = sprintf(
560             'The attribute "%s" was not found in the %s.',
561             $attribute,
562             $this->getMatchingElementRepresentation($selectorType, $selector)
563         );
564
565         $this->assertElement($element->hasAttribute($attribute), $message, $element);
566
567         return $element;
568     }
569
570     /**
571      * Checks that an attribute of a specific elements contains text.
572      *
573      * @param string       $selectorType
574      * @param string|array $selector
575      * @param string       $attribute
576      * @param string       $text
577      *
578      * @throws ElementHtmlException
579      */
580     public function elementAttributeContains($selectorType, $selector, $attribute, $text)
581     {
582         $element = $this->elementAttributeExists($selectorType, $selector, $attribute);
583         $actual = $element->getAttribute($attribute);
584         $regex = '/'.preg_quote($text, '/').'/ui';
585
586         $message = sprintf(
587             'The text "%s" was not found in the attribute "%s" of the %s.',
588             $text,
589             $attribute,
590             $this->getMatchingElementRepresentation($selectorType, $selector)
591         );
592
593         $this->assertElement((bool) preg_match($regex, $actual), $message, $element);
594     }
595
596     /**
597      * Checks that an attribute of a specific elements does not contain text.
598      *
599      * @param string       $selectorType
600      * @param string|array $selector
601      * @param string       $attribute
602      * @param string       $text
603      *
604      * @throws ElementHtmlException
605      */
606     public function elementAttributeNotContains($selectorType, $selector, $attribute, $text)
607     {
608         $element = $this->elementAttributeExists($selectorType, $selector, $attribute);
609         $actual = $element->getAttribute($attribute);
610         $regex = '/'.preg_quote($text, '/').'/ui';
611
612         $message = sprintf(
613             'The text "%s" was found in the attribute "%s" of the %s.',
614             $text,
615             $attribute,
616             $this->getMatchingElementRepresentation($selectorType, $selector)
617         );
618
619         $this->assertElement(!preg_match($regex, $actual), $message, $element);
620     }
621
622     /**
623      * Checks that specific field exists on the current page.
624      *
625      * @param string             $field     field id|name|label|value
626      * @param TraversableElement $container document to check against
627      *
628      * @return NodeElement
629      *
630      * @throws ElementNotFoundException
631      */
632     public function fieldExists($field, TraversableElement $container = null)
633     {
634         $container = $container ?: $this->session->getPage();
635         $node = $container->findField($field);
636
637         if (null === $node) {
638             throw new ElementNotFoundException($this->session->getDriver(), 'form field', 'id|name|label|value', $field);
639         }
640
641         return $node;
642     }
643
644     /**
645      * Checks that specific field does not exists on the current page.
646      *
647      * @param string             $field     field id|name|label|value
648      * @param TraversableElement $container document to check against
649      *
650      * @throws ExpectationException
651      */
652     public function fieldNotExists($field, TraversableElement $container = null)
653     {
654         $container = $container ?: $this->session->getPage();
655         $node = $container->findField($field);
656
657         $this->assert(null === $node, sprintf('A field "%s" appears on this page, but it should not.', $field));
658     }
659
660     /**
661      * Checks that specific field have provided value.
662      *
663      * @param string             $field     field id|name|label|value
664      * @param string             $value     field value
665      * @param TraversableElement $container document to check against
666      *
667      * @throws ExpectationException
668      */
669     public function fieldValueEquals($field, $value, TraversableElement $container = null)
670     {
671         $node = $this->fieldExists($field, $container);
672         $actual = $node->getValue();
673         $regex = '/^'.preg_quote($value, '/').'$/ui';
674
675         $message = sprintf('The field "%s" value is "%s", but "%s" expected.', $field, $actual, $value);
676
677         $this->assert((bool) preg_match($regex, $actual), $message);
678     }
679
680     /**
681      * Checks that specific field have provided value.
682      *
683      * @param string             $field     field id|name|label|value
684      * @param string             $value     field value
685      * @param TraversableElement $container document to check against
686      *
687      * @throws ExpectationException
688      */
689     public function fieldValueNotEquals($field, $value, TraversableElement $container = null)
690     {
691         $node = $this->fieldExists($field, $container);
692         $actual = $node->getValue();
693         $regex = '/^'.preg_quote($value, '/').'$/ui';
694
695         $message = sprintf('The field "%s" value is "%s", but it should not be.', $field, $actual);
696
697         $this->assert(!preg_match($regex, $actual), $message);
698     }
699
700     /**
701      * Checks that specific checkbox is checked.
702      *
703      * @param string             $field     field id|name|label|value
704      * @param TraversableElement $container document to check against
705      *
706      * @throws ExpectationException
707      */
708     public function checkboxChecked($field, TraversableElement $container = null)
709     {
710         $node = $this->fieldExists($field, $container);
711
712         $this->assert($node->isChecked(), sprintf('Checkbox "%s" is not checked, but it should be.', $field));
713     }
714
715     /**
716      * Checks that specific checkbox is unchecked.
717      *
718      * @param string             $field     field id|name|label|value
719      * @param TraversableElement $container document to check against
720      *
721      * @throws ExpectationException
722      */
723     public function checkboxNotChecked($field, TraversableElement $container = null)
724     {
725         $node = $this->fieldExists($field, $container);
726
727         $this->assert(!$node->isChecked(), sprintf('Checkbox "%s" is checked, but it should not be.', $field));
728     }
729
730     /**
731      * Gets current url of the page.
732      *
733      * @return string
734      */
735     protected function getCurrentUrlPath()
736     {
737         return $this->cleanUrl($this->session->getCurrentUrl());
738     }
739
740     /**
741      * Trims scriptname from the URL.
742      *
743      * @param string $url
744      *
745      * @return string
746      */
747     protected function cleanUrl($url)
748     {
749         $parts = parse_url($url);
750         $fragment = empty($parts['fragment']) ? '' : '#'.$parts['fragment'];
751         $path = empty($parts['path']) ? '/' : $parts['path'];
752
753         return preg_replace('/^\/[^\.\/]+\.php\//', '/', $path).$fragment;
754     }
755
756     /**
757      * Asserts a condition.
758      *
759      * @param bool   $condition
760      * @param string $message   Failure message
761      *
762      * @throws ExpectationException when the condition is not fulfilled
763      */
764     private function assert($condition, $message)
765     {
766         if ($condition) {
767             return;
768         }
769
770         throw new ExpectationException($message, $this->session->getDriver());
771     }
772
773     /**
774      * Asserts a condition involving the response text.
775      *
776      * @param bool   $condition
777      * @param string $message   Failure message
778      *
779      * @throws ResponseTextException when the condition is not fulfilled
780      */
781     private function assertResponseText($condition, $message)
782     {
783         if ($condition) {
784             return;
785         }
786
787         throw new ResponseTextException($message, $this->session->getDriver());
788     }
789
790     /**
791      * Asserts a condition on an element.
792      *
793      * @param bool    $condition
794      * @param string  $message   Failure message
795      * @param Element $element
796      *
797      * @throws ElementHtmlException when the condition is not fulfilled
798      */
799     private function assertElement($condition, $message, Element $element)
800     {
801         if ($condition) {
802             return;
803         }
804
805         throw new ElementHtmlException($message, $this->session->getDriver(), $element);
806     }
807
808     /**
809      * Asserts a condition involving the text of an element.
810      *
811      * @param bool    $condition
812      * @param string  $message   Failure message
813      * @param Element $element
814      *
815      * @throws ElementTextException when the condition is not fulfilled
816      */
817     private function assertElementText($condition, $message, Element $element)
818     {
819         if ($condition) {
820             return;
821         }
822
823         throw new ElementTextException($message, $this->session->getDriver(), $element);
824     }
825
826     /**
827      * @param string       $selectorType
828      * @param string|array $selector
829      * @param bool         $plural
830      *
831      * @return string
832      */
833     private function getMatchingElementRepresentation($selectorType, $selector, $plural = false)
834     {
835         $pluralization = $plural ? 's' : '';
836
837         if (in_array($selectorType, array('named', 'named_exact', 'named_partial'))
838             && is_array($selector) && 2 === count($selector)
839         ) {
840             return sprintf('%s%s matching locator "%s"', $selector[0], $pluralization, $selector[1]);
841         }
842
843         if (is_array($selector)) {
844             $selector = implode(' ', $selector);
845         }
846
847         return sprintf('element%s matching %s "%s"', $pluralization, $selectorType, $selector);
848     }
849 }