| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | <?php | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | namespace Tests; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-27 05:04:18 +08:00
										 |  |  | use Illuminate\Testing\TestResponse as BaseTestResponse; | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  | use PHPUnit\Framework\Assert as PHPUnit; | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | use Symfony\Component\DomCrawler\Crawler; | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Class TestResponse | 
					
						
							|  |  |  |  * Custom extension of the default Laravel TestResponse class. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | class TestResponse extends BaseTestResponse | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |     protected $crawlerInstance; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get the DOM Crawler for the response content. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-11-06 20:54:39 +08:00
										 |  |  |     protected function crawler(): Crawler | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         if (!is_object($this->crawlerInstance)) { | 
					
						
							|  |  |  |             $this->crawlerInstance = new Crawler($this->getContent()); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |         return $this->crawlerInstance; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-03 02:51:30 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Get the HTML of the first element at the given selector. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getElementHtml(string $selector): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->crawler()->filter($selector)->first()->outerHtml(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Assert the response contains the specified element. | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |      * @return $this | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function assertElementExists(string $selector) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $elements = $this->crawler()->filter($selector); | 
					
						
							|  |  |  |         PHPUnit::assertTrue( | 
					
						
							|  |  |  |             $elements->count() > 0, | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |             'Unable to find element matching the selector: ' . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             "[{$selector}]" . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             'within' . PHP_EOL . PHP_EOL . | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |             "[{$this->getContent()}]." | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-07 05:54:02 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Assert the response contains the given count of elements | 
					
						
							|  |  |  |      * that match the given css selector. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return $this | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function assertElementCount(string $selector, int $count) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $elements = $this->crawler()->filter($selector); | 
					
						
							|  |  |  |         PHPUnit::assertTrue( | 
					
						
							|  |  |  |             $elements->count() === $count, | 
					
						
							|  |  |  |             'Unable to ' . $count . ' element(s) matching the selector: ' . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             "[{$selector}]" . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             'found ' . $elements->count() . ' within' . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             "[{$this->getContent()}]." | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Assert the response does not contain the specified element. | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |      * @return $this | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function assertElementNotExists(string $selector) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $elements = $this->crawler()->filter($selector); | 
					
						
							|  |  |  |         PHPUnit::assertTrue( | 
					
						
							|  |  |  |             $elements->count() === 0, | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |             'Found elements matching the selector: ' . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             "[{$selector}]" . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             'within' . PHP_EOL . PHP_EOL . | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |             "[{$this->getContent()}]." | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Assert the response includes a specific element containing the given text. | 
					
						
							| 
									
										
										
										
											2021-03-22 07:06:15 +08:00
										 |  |  |      * If an nth match is provided, only that will be checked otherwise all matching | 
					
						
							|  |  |  |      * elements will be checked for the given text. | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |      * @return $this | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-03-22 07:06:15 +08:00
										 |  |  |     public function assertElementContains(string $selector, string $text, ?int $nthMatch = null) | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         $elements = $this->crawler()->filter($selector); | 
					
						
							|  |  |  |         $matched = false; | 
					
						
							|  |  |  |         $pattern = $this->getEscapedPattern($text); | 
					
						
							| 
									
										
										
										
											2021-03-22 07:06:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (!is_null($nthMatch)) { | 
					
						
							|  |  |  |             $elements = $elements->eq($nthMatch - 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |         foreach ($elements as $element) { | 
					
						
							|  |  |  |             $element = new Crawler($element); | 
					
						
							| 
									
										
										
										
											2022-05-16 21:05:21 +08:00
										 |  |  |             if (preg_match("/$pattern/i", $element->text())) { | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |                 $matched = true; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         PHPUnit::assertTrue( | 
					
						
							|  |  |  |             $matched, | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |             'Unable to find element of selector: ' . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             ($nthMatch ? ("at position {$nthMatch}" . PHP_EOL . PHP_EOL) : '') . | 
					
						
							|  |  |  |             "[{$selector}]" . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             'containing text' . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             "[{$text}]" . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             'within' . PHP_EOL . PHP_EOL . | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |             "[{$this->getContent()}]." | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Assert the response does not include a specific element containing the given text. | 
					
						
							| 
									
										
										
										
											2021-03-22 07:06:15 +08:00
										 |  |  |      * If an nth match is provided, only that will be checked otherwise all matching | 
					
						
							|  |  |  |      * elements will be checked for the given text. | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |      * @return $this | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-03-22 07:06:15 +08:00
										 |  |  |     public function assertElementNotContains(string $selector, string $text, ?int $nthMatch = null) | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         $elements = $this->crawler()->filter($selector); | 
					
						
							|  |  |  |         $matched = false; | 
					
						
							|  |  |  |         $pattern = $this->getEscapedPattern($text); | 
					
						
							| 
									
										
										
										
											2021-03-22 07:06:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (!is_null($nthMatch)) { | 
					
						
							|  |  |  |             $elements = $elements->eq($nthMatch - 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |         foreach ($elements as $element) { | 
					
						
							|  |  |  |             $element = new Crawler($element); | 
					
						
							|  |  |  |             if (preg_match("/$pattern/i", $element->html())) { | 
					
						
							|  |  |  |                 $matched = true; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         PHPUnit::assertTrue( | 
					
						
							|  |  |  |             !$matched, | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |             'Found element of selector: ' . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             ($nthMatch ? ("at position {$nthMatch}" . PHP_EOL . PHP_EOL) : '') . | 
					
						
							|  |  |  |             "[{$selector}]" . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             'containing text' . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             "[{$text}]" . PHP_EOL . PHP_EOL . | 
					
						
							|  |  |  |             'within' . PHP_EOL . PHP_EOL . | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |             "[{$this->getContent()}]." | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-06 20:54:39 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Assert there's a notification within the view containing the given text. | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2020-11-06 20:54:39 +08:00
										 |  |  |      * @return $this | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function assertNotificationContains(string $text) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->assertElementContains('[notification]', $text); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Get the escaped text pattern for the constraint. | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |      * @return string | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-11-06 20:54:39 +08:00
										 |  |  |     protected function getEscapedPattern(string $text) | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         $rawPattern = preg_quote($text, '/'); | 
					
						
							|  |  |  |         $escapedPattern = preg_quote(e($text), '/'); | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-21 22:15:16 +08:00
										 |  |  |         return $rawPattern == $escapedPattern | 
					
						
							|  |  |  |             ? $rawPattern : "({$rawPattern}|{$escapedPattern})"; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |