PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Codeception/Lib/InnerBrowser.php

https://github.com/pmcjury/Codeception
PHP | 791 lines | 650 code | 69 blank | 72 comment | 56 complexity | a05f89ecf759e621a8203a429243ce9f MD5 | raw file
  1. <?php
  2. namespace Codeception\Lib;
  3. use Codeception\Exception\ElementNotFound;
  4. use Codeception\Exception\TestRuntime;
  5. use Codeception\PHPUnit\Constraint\Page as PageConstraint;
  6. use Codeception\PHPUnit\Constraint\Crawler as CrawlerConstraint;
  7. use Codeception\PHPUnit\Constraint\CrawlerNot as CrawlerNotConstraint;
  8. use Codeception\Module;
  9. use Codeception\TestCase;
  10. use Codeception\Util\Locator;
  11. use Codeception\Lib\Interfaces\Web;
  12. use Symfony\Component\BrowserKit\Cookie;
  13. use Symfony\Component\CssSelector\CssSelector;
  14. use Symfony\Component\CssSelector\Exception\ParseException;
  15. use Symfony\Component\DomCrawler\Crawler;
  16. class InnerBrowser extends Module implements Web
  17. {
  18. /**
  19. * @var \Symfony\Component\DomCrawler\Crawler
  20. */
  21. protected $crawler;
  22. /**
  23. * @api
  24. * @var \Symfony\Component\BrowserKit\Client
  25. */
  26. public $client;
  27. protected $forms = array();
  28. public function _failed(TestCase $test, $fail)
  29. {
  30. if (!$this->client || !$this->client->getInternalResponse()) {
  31. return;
  32. }
  33. $filename = str_replace(['::','\\','/'], ['.','',''], \Codeception\TestCase::getTestSignature($test)).'.fail.html';
  34. file_put_contents(codecept_output_dir($filename), $this->client->getInternalResponse()->getContent());
  35. }
  36. public function _after(TestCase $test)
  37. {
  38. $this->client = null;
  39. $this->crawler = null;
  40. $this->forms = array();
  41. }
  42. /**
  43. * Authenticates user for HTTP_AUTH
  44. *
  45. * @param $username
  46. * @param $password
  47. */
  48. public function amHttpAuthenticated($username, $password)
  49. {
  50. $this->client->setServerParameter('PHP_AUTH_USER', $username);
  51. $this->client->setServerParameter('PHP_AUTH_PW', $password);
  52. }
  53. public function amOnPage($page)
  54. {
  55. $this->crawler = $this->client->request('GET', $page);
  56. $this->forms = [];
  57. $this->debugResponse();
  58. }
  59. public function click($link, $context = null)
  60. {
  61. if ($context) {
  62. $this->crawler = $this->match($context);
  63. }
  64. if (is_array($link)) {
  65. $this->clickByLocator($link);
  66. return;
  67. }
  68. $anchor = $this->strictMatch(['link' => $link]);
  69. if (!count($anchor)) {
  70. $anchor = $this->crawler->selectLink($link);
  71. }
  72. if (count($anchor)) {
  73. $this->crawler = $this->client->click($anchor->first()->link());
  74. $this->forms = [];
  75. $this->debugResponse();
  76. return;
  77. }
  78. $button = $this->crawler->selectButton($link);
  79. if (count($button)) {
  80. $this->submitFormWithButton($button);
  81. $this->debugResponse();
  82. return;
  83. }
  84. $this->clickByLocator($link);
  85. }
  86. protected function clickByLocator($link)
  87. {
  88. $nodes = $this->match($link);
  89. if (!$nodes->count()) {
  90. throw new ElementNotFound($link, 'Link or Button by name or CSS or XPath');
  91. }
  92. foreach ($nodes as $node) {
  93. $tag = $node->nodeName;
  94. $type = $node->getAttribute('type');
  95. if ($tag == 'a') {
  96. $this->crawler = $this->client->click($nodes->first()->link());
  97. $this->forms = [];
  98. $this->debugResponse();
  99. return;
  100. } elseif(
  101. ($tag == 'input' && in_array($type, array('submit', 'image'))) ||
  102. ($tag == 'button' && $type == 'submit'))
  103. {
  104. $this->submitFormWithButton($nodes->first());
  105. $this->debugResponse();
  106. return;
  107. }
  108. }
  109. }
  110. protected function submitFormWithButton($button)
  111. {
  112. foreach ($button as $node) {
  113. if (!$node->getAttribute('name')) {
  114. $node->setAttribute('name', 'codeception_generated_button_name');
  115. }
  116. }
  117. $domForm = $button->form();
  118. $form = $this->getFormFor($button);
  119. $this->debugSection('Uri', $domForm->getUri());
  120. $this->debugSection($domForm->getMethod(), $form->getValues());
  121. $this->crawler = $this->client->request($domForm->getMethod(), $domForm->getUri(), $form->getPhpValues(), $form->getPhpFiles());
  122. $this->forms = [];
  123. }
  124. public function see($text, $selector = null)
  125. {
  126. if (!$selector) {
  127. $this->assertPageContains($text);
  128. } else {
  129. $nodes = $this->match($selector);
  130. $this->assertDomContains($nodes, $selector, $text);
  131. }
  132. }
  133. public function dontSee($text, $selector = null)
  134. {
  135. if (!$selector) {
  136. $this->assertPageNotContains($text);
  137. } else {
  138. $nodes = $this->match($selector);
  139. $this->assertDomNotContains($nodes, $selector, $text);
  140. }
  141. }
  142. public function seeLink($text, $url = null)
  143. {
  144. $links = $this->crawler->selectLink($text);
  145. if ($url) {
  146. $links = $links->filterXPath(sprintf('.//a[contains(@href, %s)]', Crawler::xpathLiteral($url)));
  147. }
  148. $this->assertDomContains($links, 'a');
  149. }
  150. public function dontSeeLink($text, $url = null)
  151. {
  152. $links = $this->crawler->selectLink($text);
  153. if ($url) {
  154. $links = $links->filterXPath(sprintf('.//a[contains(@href, %s)]', Crawler::xpathLiteral($url)));
  155. }
  156. $this->assertDomNotContains($links, 'a');
  157. }
  158. public function _getCurrentUri()
  159. {
  160. $url = $this->client->getHistory()->current()->getUri();
  161. $parts = parse_url($url);
  162. if (!$parts) {
  163. $this->fail("URL couldn't be parsed");
  164. }
  165. $uri = "";
  166. if (isset($parts['path'])) {
  167. $uri .= $parts['path'];
  168. }
  169. if (isset($parts['query'])) {
  170. $uri .= "?" . $parts['query'];
  171. }
  172. return $uri;
  173. }
  174. public function seeInCurrentUrl($uri)
  175. {
  176. $this->assertContains($uri, $this->_getCurrentUri());
  177. }
  178. public function dontSeeInCurrentUrl($uri)
  179. {
  180. $this->assertNotContains($uri, $this->_getCurrentUri());
  181. }
  182. public function seeCurrentUrlEquals($uri)
  183. {
  184. $this->assertEquals($uri, $this->_getCurrentUri());
  185. }
  186. public function dontSeeCurrentUrlEquals($uri)
  187. {
  188. $this->assertNotEquals($uri, $this->_getCurrentUri());
  189. }
  190. public function seeCurrentUrlMatches($uri)
  191. {
  192. \PHPUnit_Framework_Assert::assertRegExp($uri, $this->_getCurrentUri());
  193. }
  194. public function dontSeeCurrentUrlMatches($uri)
  195. {
  196. \PHPUnit_Framework_Assert::assertNotRegExp($uri, $this->_getCurrentUri());
  197. }
  198. public function grabFromCurrentUrl($uri = null)
  199. {
  200. if (!$uri) {
  201. return $this->_getCurrentUri();
  202. }
  203. $matches = array();
  204. $res = preg_match($uri, $this->_getCurrentUri(), $matches);
  205. if (!$res) {
  206. $this->fail("Couldn't match $uri in " . $this->_getCurrentUri());
  207. }
  208. if (!isset($matches[1])) {
  209. $this->fail("Nothing to grab. A regex parameter required. Ex: '/user/(\\d+)'");
  210. }
  211. return $matches[1];
  212. }
  213. public function seeCheckboxIsChecked($checkbox)
  214. {
  215. $checkboxes = $this->crawler->filter($checkbox);
  216. $this->assertDomContains($checkboxes->filter('input[checked=checked]'), 'checkbox');
  217. }
  218. public function dontSeeCheckboxIsChecked($checkbox)
  219. {
  220. $checkboxes = $this->crawler->filter($checkbox);
  221. \PHPUnit_Framework_Assert::assertEquals(0, $checkboxes->filter('input[checked=checked]')->count());
  222. }
  223. public function seeInField($field, $value)
  224. {
  225. $this->assert($this->proceedSeeInField($field, $value));
  226. }
  227. public function dontSeeInField($field, $value)
  228. {
  229. $this->assertNot($this->proceedSeeInField($field, $value));
  230. }
  231. protected function proceedSeeInField($field, $value)
  232. {
  233. $field = $this->getFieldByLabelOrCss($field);
  234. if (empty($field)) {
  235. throw new ElementNotFound('Input field');
  236. }
  237. $currentValue = $field->filter('textarea')->extract(array('_text'));
  238. if (!$currentValue) {
  239. $currentValue = $field->extract(array('value'));
  240. }
  241. return array('Contains', $value, $currentValue);
  242. }
  243. public function submitForm($selector, $params)
  244. {
  245. $form = $this->match($selector)->first();
  246. if (!count($form)) {
  247. throw new ElementNotFound($selector, 'Form');
  248. }
  249. $url = '';
  250. $fields = $form->filter('input');
  251. foreach ($fields as $field) {
  252. if ($field->getAttribute('type') == 'checkbox') {
  253. continue;
  254. }
  255. if ($field->getAttribute('type') == 'radio') {
  256. continue;
  257. }
  258. $url .= sprintf('%s=%s', $field->getAttribute('name'), $field->getAttribute('value')) . '&';
  259. }
  260. $fields = $form->filter('textarea');
  261. foreach ($fields as $field) {
  262. $url .= sprintf('%s=%s', $field->getAttribute('name'), $field->nodeValue) . '&';
  263. }
  264. $fields = $form->filter('select');
  265. foreach ($fields as $field) {
  266. foreach ($field->childNodes as $option) {
  267. if ($option->getAttribute('selected') == 'selected') {
  268. $url .= sprintf('%s=%s', $field->getAttribute('name'), $option->getAttribute('value')) . '&';
  269. }
  270. }
  271. }
  272. $url .= http_build_query($params);
  273. parse_str($url, $params);
  274. $method = $form->attr('method') ? $form->attr('method') : 'GET';
  275. $query = '';
  276. if (strtoupper($method) == 'GET') {
  277. $query = '?' . http_build_query($params);
  278. }
  279. $this->debugSection('Uri', $this->getFormUrl($form));
  280. $this->debugSection('Method', $method);
  281. $this->debugSection('Parameters', $params);
  282. $this->crawler = $this->client->request($method, $this->getFormUrl($form) . $query, $params);
  283. $this->debugResponse();
  284. }
  285. protected function getFormUrl($form)
  286. {
  287. $action = $form->attr('action');
  288. if ((!$action) or ($action == '#')) {
  289. $action = $this->client->getHistory()->current()->getUri();
  290. }
  291. return $action;
  292. }
  293. protected function getFormFor($node)
  294. {
  295. $form = $node->parents()->filter('form')->first();
  296. if (!$form) {
  297. $this->fail('The selected node does not have a form ancestor.');
  298. }
  299. $action = $this->getFormUrl($form);
  300. if (!isset($this->forms[$action])) {
  301. $submit = new \DOMElement('input');
  302. $submit = $form->current()->appendChild($submit);
  303. $submit->setAttribute('type', 'submit'); // for forms with no submits
  304. $submit->setAttribute('name', 'codeception_added_auto_submit');
  305. // Symfony2.1 DOM component requires name for each field.
  306. if (!$form->filter('*[type=submit]')->attr('name')) {
  307. $form = $form->filter('*[type=submit][name=codeception_added_auto_submit]')->form();
  308. } else {
  309. $form = $form->filter('*[type=submit]')->form();
  310. }
  311. $this->forms[$action] = $form;
  312. }
  313. return $this->forms[$action];
  314. }
  315. public function fillField($field, $value)
  316. {
  317. $input = $this->getFieldByLabelOrCss($field);
  318. $form = $this->getFormFor($input);
  319. $form[$input->attr('name')] = $value;
  320. }
  321. protected function getFieldByLabelOrCss($field)
  322. {
  323. if (is_array($field)) {
  324. $input = $this->strictMatch($field);
  325. if (!count($input)) {
  326. throw new ElementNotFound($field);
  327. }
  328. return $input->first();
  329. }
  330. // by label
  331. $label = $this->strictMatch(['xpath' => sprintf('.//label[text()=%s]', Crawler::xpathLiteral($field))]);
  332. if (count($label)) {
  333. $label = $label->first();
  334. if ($label->attr('for')) {
  335. $input = $this->strictMatch(['id' => $label->attr('for')]);
  336. }
  337. }
  338. // by name
  339. if (!isset($input)) {
  340. $input = $this->strictMatch(['name' => $field]);
  341. }
  342. // by CSS and XPath
  343. if (!count($input)) {
  344. $input = $this->match($field);
  345. }
  346. if (!count($input)) {
  347. throw new ElementNotFound($field, 'Form field by Label or CSS');
  348. }
  349. return $input->first();
  350. }
  351. public function selectOption($select, $option)
  352. {
  353. $field = $this->getFieldByLabelOrCss($select);
  354. $form = $this->getFormFor($field);
  355. $fieldName = $field->attr('name');
  356. if ($field->attr('multiple')) {
  357. $fieldName = str_replace('[]', '', $fieldName);
  358. }
  359. if (is_array($option)) {
  360. $options = array();
  361. foreach ($option as $opt) {
  362. $options[] = $this->matchOption($field, $opt);
  363. }
  364. $form[$fieldName]->select($options);
  365. return;
  366. }
  367. $form[$fieldName]->select($this->matchOption($field, $option));
  368. }
  369. protected function matchOption(Crawler $field, $option)
  370. {
  371. $options = $field->filterXPath(sprintf('//option[text()=normalize-space("%s")]', $option));
  372. if ($options->count()) {
  373. return $options->first()->attr('value');
  374. }
  375. return $option;
  376. }
  377. public function checkOption($option)
  378. {
  379. $form = $this->getFormFor($field = $this->getFieldByLabelOrCss($option));
  380. $form[$field->attr('name')]->tick();
  381. }
  382. public function uncheckOption($option)
  383. {
  384. $form = $this->getFormFor($field = $this->getFieldByLabelOrCss($option));
  385. $form[$field->attr('name')]->untick();
  386. }
  387. public function attachFile($field, $filename)
  388. {
  389. $form = $this->getFormFor($field = $this->getFieldByLabelOrCss($field));
  390. $path = \Codeception\Configuration::dataDir() . $filename;
  391. if (!is_readable($path)) {
  392. $this->fail(
  393. "file $filename not found in Codeception data path. Only files stored in data path accepted"
  394. );
  395. }
  396. $form[$field->attr('name')]->upload($path);
  397. }
  398. /**
  399. * If your page triggers an ajax request, you can perform it manually.
  400. * This action sends a GET ajax request with specified params.
  401. *
  402. * See ->sendAjaxPostRequest for examples.
  403. *
  404. * @param $uri
  405. * @param $params
  406. */
  407. public function sendAjaxGetRequest($uri, $params = array())
  408. {
  409. $this->sendAjaxRequest('GET', $uri, $params);
  410. }
  411. /**
  412. * If your page triggers an ajax request, you can perform it manually.
  413. * This action sends a POST ajax request with specified params.
  414. * Additional params can be passed as array.
  415. *
  416. * Example:
  417. *
  418. * Imagine that by clicking checkbox you trigger ajax request which updates user settings.
  419. * We emulate that click by running this ajax request manually.
  420. *
  421. * ``` php
  422. * <?php
  423. * $I->sendAjaxPostRequest('/updateSettings', array('notifications' => true)); // POST
  424. * $I->sendAjaxGetRequest('/updateSettings', array('notifications' => true)); // GET
  425. *
  426. * ```
  427. *
  428. * @param $uri
  429. * @param $params
  430. */
  431. public function sendAjaxPostRequest($uri, $params = array())
  432. {
  433. $this->sendAjaxRequest('POST', $uri, $params);
  434. }
  435. /**
  436. * If your page triggers an ajax request, you can perform it manually.
  437. * This action sends an ajax request with specified method and params.
  438. *
  439. * Example:
  440. *
  441. * You need to perform an ajax request specifying the HTTP method.
  442. *
  443. * ``` php
  444. * <?php
  445. * $I->sendAjaxRequest('PUT', /posts/7', array('title' => 'new title');
  446. *
  447. * ```
  448. *
  449. * @param $method
  450. * @param $uri
  451. * @param $params
  452. */
  453. public function sendAjaxRequest($method, $uri, $params = array())
  454. {
  455. $this->client->request($method, $uri, $params, array(), array('HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'));
  456. $this->debugResponse();
  457. }
  458. protected function debugResponse()
  459. {
  460. $this->debugSection('Response', $this->getResponseStatusCode());
  461. $this->debugSection('Page', $this->client->getHistory()->current()->getUri());
  462. $this->debugSection('Cookies', $this->client->getInternalRequest()->getCookies());
  463. $this->debugSection('Headers', $this->client->getInternalResponse()->getHeaders());
  464. }
  465. protected function getResponseStatusCode()
  466. {
  467. // depending on Symfony version
  468. $response = $this->client->getInternalResponse();
  469. if (method_exists($response, 'getStatus')) {
  470. return $response->getStatus();
  471. }
  472. if (method_exists($response, 'getStatusCode')) {
  473. return $response->getStatusCode();
  474. }
  475. return "N/A";
  476. }
  477. /**
  478. * @return Crawler
  479. */
  480. protected function match($selector)
  481. {
  482. if (is_array($selector)) {
  483. return $this->strictMatch($selector);
  484. }
  485. try {
  486. $selector = CssSelector::toXPath($selector);
  487. } catch (ParseException $e) {
  488. }
  489. if (!Locator::isXPath($selector)) {
  490. return null;
  491. }
  492. return @$this->crawler->filterXPath($selector);
  493. }
  494. protected function strictMatch(array $by)
  495. {
  496. $type = key($by);
  497. $locator = $by[$type];
  498. switch ($type) {
  499. case 'id':
  500. return $this->crawler->filter("#$locator");
  501. case 'name':
  502. return @$this->crawler->filterXPath(sprintf('.//*[@name=%s]', Crawler::xpathLiteral($locator)));
  503. case 'css':
  504. return $this->crawler->filter($locator);
  505. case 'xpath':
  506. return @$this->crawler->filterXPath($locator);
  507. case 'link':
  508. return @$this->crawler->filterXPath(sprintf('.//a[.=%s]', Crawler::xpathLiteral($locator)));
  509. case 'class':
  510. return $this->crawler->filter(".$locator");
  511. default:
  512. throw new TestRuntime("Locator type '$by' is not defined. Use either: xpath, css, id, link, class, name");
  513. }
  514. }
  515. protected function filterByAttributes(Crawler $nodes, array $attributes)
  516. {
  517. foreach ($attributes as $attr => $val) {
  518. $nodes = $nodes->reduce(function(Crawler $node) use ($attr, $val) {
  519. return $node->attr($attr) == $val;
  520. });
  521. }
  522. return $nodes;
  523. }
  524. public function grabTextFrom($cssOrXPathOrRegex)
  525. {
  526. $nodes = $this->match($cssOrXPathOrRegex);
  527. if ($nodes) {
  528. return $nodes->first()->text();
  529. }
  530. if (@preg_match($cssOrXPathOrRegex, $this->client->getInternalResponse()->getContent(), $matches)) {
  531. return $matches[1];
  532. }
  533. throw new ElementNotFound($cssOrXPathOrRegex, 'Element that matches CSS or XPath or Regex');
  534. }
  535. public function grabAttributeFrom($cssOrXpath, $attribute)
  536. {
  537. $nodes = $this->match($cssOrXpath);
  538. if (!$nodes->count()) {
  539. throw new ElementNotFound($cssOrXpath, 'Element that matches CSS or XPath');
  540. }
  541. return $nodes->first()->attr($attribute);
  542. }
  543. public function grabValueFrom($field)
  544. {
  545. $nodes = $this->match($field);
  546. if (!$nodes->count()) {
  547. throw new ElementNotFound($field, 'Field');
  548. }
  549. if ($nodes->filter('textarea')->count()) {
  550. return $nodes->filter('textarea')->text();
  551. }
  552. if ($nodes->filter('input')->count()) {
  553. return $nodes->filter('input')->attr('value');
  554. }
  555. if ($nodes->filter('select')->count()) {
  556. $select = $nodes->filter('select');
  557. $is_multiple = $select->attr('multiple');
  558. $results = array();
  559. foreach ($select->childNodes as $option) {
  560. if ($option->getAttribute('selected') == 'selected') {
  561. $val = $option->attr('value');
  562. if (!$is_multiple) {
  563. return $val;
  564. }
  565. $results[] = $val;
  566. }
  567. }
  568. if (!$is_multiple) {
  569. return null;
  570. }
  571. return $results;
  572. }
  573. $this->fail("Element $field is not a form field or does not contain a form field");
  574. }
  575. public function setCookie($name, $val)
  576. {
  577. $cookies = $this->client->getCookieJar();
  578. $cookies->set(new Cookie($name, $val));
  579. $this->debugSection('Cookies', $this->client->getCookieJar()->all());
  580. }
  581. public function grabCookie($name)
  582. {
  583. $this->debugSection('Cookies', $this->client->getCookieJar()->all());
  584. $cookies = $this->client->getCookieJar()->get($name);
  585. if (!$cookies) {
  586. return null;
  587. }
  588. return $cookies->getValue();
  589. }
  590. public function seeCookie($name)
  591. {
  592. $this->debugSection('Cookies', $this->client->getCookieJar()->all());
  593. $this->assertNotNull($this->client->getCookieJar()->get($name));
  594. }
  595. public function dontSeeCookie($name)
  596. {
  597. $this->debugSection('Cookies', $this->client->getCookieJar()->all());
  598. $this->assertNull($this->client->getCookieJar()->get($name));
  599. }
  600. public function resetCookie($name)
  601. {
  602. $this->client->getCookieJar()->expire($name);
  603. $this->debugSection('Cookies', $this->client->getCookieJar()->all());
  604. }
  605. public function seeElement($selector, $attributes = array())
  606. {
  607. $nodes = $this->match($selector);
  608. if (!empty($attributes)) {
  609. $nodes = $this->filterByAttributes($nodes, $attributes);
  610. $selector .= "' with attribute(s) '" . trim(json_encode($attributes),'{}');
  611. }
  612. $this->assertDomContains($nodes, $selector);
  613. }
  614. public function dontSeeElement($selector, $attributes = array())
  615. {
  616. $nodes = $this->match($selector);
  617. if (!empty($attributes)) {
  618. $nodes = $this->filterByAttributes($nodes, $attributes);
  619. $selector .= "' with attribute(s) '" . trim(json_encode($attributes),'{}');
  620. }
  621. $this->assertDomNotContains($nodes, $selector);
  622. }
  623. public function seeOptionIsSelected($select, $optionText)
  624. {
  625. $selected = $this->matchSelectedOption($select);
  626. $this->assertDomContains($selected, 'selected option');
  627. $this->assertEquals($optionText, $selected->text());
  628. }
  629. public function dontSeeOptionIsSelected($select, $optionText)
  630. {
  631. $selected = $this->matchSelectedOption($select);
  632. if (!$selected->count()) {
  633. $this->assertEquals(0, $selected->count());
  634. return;
  635. }
  636. $this->assertNotEquals($optionText, $selected->text());
  637. }
  638. protected function matchSelectedOption($select)
  639. {
  640. $nodes = $this->getFieldByLabelOrCss($select);
  641. return $nodes->first()->filter('option[selected]');
  642. }
  643. /**
  644. * Asserts that current page has 404 response status code.
  645. */
  646. public function seePageNotFound()
  647. {
  648. $this->seeResponseCodeIs(404);
  649. }
  650. /**
  651. * Checks that response code is equal to value provided.
  652. *
  653. * @param $code
  654. *
  655. * @return mixed
  656. */
  657. public function seeResponseCodeIs($code)
  658. {
  659. $this->assertEquals($code, $this->getResponseStatusCode());
  660. }
  661. public function seeInTitle($title)
  662. {
  663. $nodes = $this->crawler->filter('title');
  664. if (!$nodes->count()) {
  665. throw new ElementNotFound("<title>","Tag");
  666. }
  667. $this->assertContains($title, $nodes->first()->text(), "page title contains $title");
  668. }
  669. public function dontSeeInTitle($title)
  670. {
  671. $nodes = $this->crawler->filter('title');
  672. if (!$nodes->count()) {
  673. $this->assertTrue(true);
  674. return;
  675. }
  676. $this->assertNotContains($title, $nodes->first()->text(), "page title contains $title");
  677. }
  678. protected function assertDomContains($nodes, $message, $text = '')
  679. {
  680. $constraint = new CrawlerConstraint($text, $this->_getCurrentUri());
  681. $this->assertThat($nodes, $constraint, $message);
  682. }
  683. protected function assertDomNotContains($nodes, $message, $text = '')
  684. {
  685. $constraint = new CrawlerNotConstraint($text, $this->_getCurrentUri());
  686. $this->assertThat($nodes, $constraint, $message);
  687. }
  688. protected function assertPageContains($needle, $message = '')
  689. {
  690. $constraint = new PageConstraint($needle, $this->_getCurrentUri());
  691. $this->assertThat($this->client->getInternalResponse()->getContent(), $constraint,$message);
  692. }
  693. protected function assertPageNotContains($needle, $message = '')
  694. {
  695. $constraint = new PageConstraint($needle, $this->_getCurrentUri());
  696. $this->assertThatItsNot($this->client->getInternalResponse()->getContent(), $constraint,$message);
  697. }
  698. }