CrawlerTest.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.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. namespace Symfony\Component\DomCrawler\Tests;
  11. use Symfony\Component\DomCrawler\Crawler;
  12. class CrawlerTest extends \PHPUnit_Framework_TestCase
  13. {
  14. public function testConstructor()
  15. {
  16. $crawler = new Crawler();
  17. $this->assertCount(0, $crawler, '__construct() returns an empty crawler');
  18. $crawler = new Crawler(new \DOMNode());
  19. $this->assertCount(1, $crawler, '__construct() takes a node as a first argument');
  20. }
  21. /**
  22. * @covers Symfony\Component\DomCrawler\Crawler::add
  23. */
  24. public function testAdd()
  25. {
  26. $crawler = new Crawler();
  27. $crawler->add($this->createDomDocument());
  28. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->add() adds nodes from a \DOMDocument');
  29. $crawler = new Crawler();
  30. $crawler->add($this->createNodeList());
  31. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->add() adds nodes from a \DOMNodeList');
  32. foreach ($this->createNodeList() as $node) {
  33. $list[] = $node;
  34. }
  35. $crawler = new Crawler();
  36. $crawler->add($list);
  37. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->add() adds nodes from an array of nodes');
  38. $crawler = new Crawler();
  39. $crawler->add($this->createNodeList()->item(0));
  40. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->add() adds nodes from an \DOMNode');
  41. $crawler = new Crawler();
  42. $crawler->add('<html><body>Foo</body></html>');
  43. $this->assertEquals('Foo', $crawler->filterXPath('//body')->text(), '->add() adds nodes from a string');
  44. }
  45. /**
  46. * @expectedException \InvalidArgumentException
  47. */
  48. public function testAddInvalidNode()
  49. {
  50. $crawler = new Crawler();
  51. $crawler->add(1);
  52. }
  53. /**
  54. * @covers Symfony\Component\DomCrawler\Crawler::addHtmlContent
  55. */
  56. public function testAddHtmlContent()
  57. {
  58. $crawler = new Crawler();
  59. $crawler->addHtmlContent('<html><div class="foo"></html>', 'UTF-8');
  60. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addHtmlContent() adds nodes from an HTML string');
  61. $crawler->addHtmlContent('<html><head><base href="http://symfony.com"></head><a href="/contact"></a></html>', 'UTF-8');
  62. $this->assertEquals('http://symfony.com', $crawler->filterXPath('//base')->attr('href'), '->addHtmlContent() adds nodes from an HTML string');
  63. $this->assertEquals('http://symfony.com/contact', $crawler->filterXPath('//a')->link()->getUri(), '->addHtmlContent() adds nodes from an HTML string');
  64. }
  65. /**
  66. * @covers Symfony\Component\DomCrawler\Crawler::addHtmlContent
  67. */
  68. public function testAddHtmlContentCharset()
  69. {
  70. $crawler = new Crawler();
  71. $crawler->addHtmlContent('<html><div class="foo">Tiếng Việt</html>', 'UTF-8');
  72. $this->assertEquals('Tiếng Việt', $crawler->filterXPath('//div')->text());
  73. }
  74. /**
  75. * @covers Symfony\Component\DomCrawler\Crawler::addHtmlContent
  76. */
  77. public function testAddHtmlContentInvalidBaseTag()
  78. {
  79. $crawler = new Crawler(null, 'http://symfony.com');
  80. $crawler->addHtmlContent('<html><head><base target="_top"></head><a href="/contact"></a></html>', 'UTF-8');
  81. $this->assertEquals('http://symfony.com/contact', current($crawler->filterXPath('//a')->links())->getUri(), '->addHtmlContent() correctly handles a non-existent base tag href attribute');
  82. }
  83. /**
  84. * @covers Symfony\Component\DomCrawler\Crawler::addHtmlContent
  85. */
  86. public function testAddHtmlContentUnsupportedCharset()
  87. {
  88. $crawler = new Crawler();
  89. $crawler->addHtmlContent(file_get_contents(__DIR__.'/Fixtures/windows-1250.html'), 'Windows-1250');
  90. $this->assertEquals('Žťčýů', $crawler->filterXPath('//p')->text());
  91. }
  92. /**
  93. * @covers Symfony\Component\DomCrawler\Crawler::addHtmlContent
  94. */
  95. public function testAddHtmlContentWithErrors()
  96. {
  97. libxml_use_internal_errors(true);
  98. $crawler = new Crawler();
  99. $crawler->addHtmlContent(<<<EOF
  100. <!DOCTYPE html>
  101. <html>
  102. <head>
  103. </head>
  104. <body>
  105. <nav><a href="#"><a href="#"></nav>
  106. </body>
  107. </html>
  108. EOF
  109. , 'UTF-8');
  110. $errors = libxml_get_errors();
  111. $this->assertCount(1, $errors);
  112. $this->assertEquals("Tag nav invalid\n", $errors[0]->message);
  113. libxml_clear_errors();
  114. libxml_use_internal_errors(false);
  115. }
  116. /**
  117. * @covers Symfony\Component\DomCrawler\Crawler::addXmlContent
  118. */
  119. public function testAddXmlContent()
  120. {
  121. $crawler = new Crawler();
  122. $crawler->addXmlContent('<html><div class="foo"></div></html>', 'UTF-8');
  123. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addXmlContent() adds nodes from an XML string');
  124. }
  125. /**
  126. * @covers Symfony\Component\DomCrawler\Crawler::addXmlContent
  127. */
  128. public function testAddXmlContentCharset()
  129. {
  130. $crawler = new Crawler();
  131. $crawler->addXmlContent('<html><div class="foo">Tiếng Việt</div></html>', 'UTF-8');
  132. $this->assertEquals('Tiếng Việt', $crawler->filterXPath('//div')->text());
  133. }
  134. /**
  135. * @covers Symfony\Component\DomCrawler\Crawler::addXmlContent
  136. */
  137. public function testAddXmlContentWithErrors()
  138. {
  139. libxml_use_internal_errors(true);
  140. $crawler = new Crawler();
  141. $crawler->addXmlContent(<<<EOF
  142. <!DOCTYPE html>
  143. <html>
  144. <head>
  145. </head>
  146. <body>
  147. <nav><a href="#"><a href="#"></nav>
  148. </body>
  149. </html>
  150. EOF
  151. , 'UTF-8');
  152. $this->assertTrue(count(libxml_get_errors()) > 1);
  153. libxml_clear_errors();
  154. libxml_use_internal_errors(false);
  155. }
  156. /**
  157. * @covers Symfony\Component\DomCrawler\Crawler::addContent
  158. */
  159. public function testAddContent()
  160. {
  161. $crawler = new Crawler();
  162. $crawler->addContent('<html><div class="foo"></html>', 'text/html; charset=UTF-8');
  163. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an HTML string');
  164. $crawler = new Crawler();
  165. $crawler->addContent('<html><div class="foo"></html>', 'text/html; charset=UTF-8; dir=RTL');
  166. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an HTML string with extended content type');
  167. $crawler = new Crawler();
  168. $crawler->addContent('<html><div class="foo"></html>');
  169. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() uses text/html as the default type');
  170. $crawler = new Crawler();
  171. $crawler->addContent('<html><div class="foo"></div></html>', 'text/xml; charset=UTF-8');
  172. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an XML string');
  173. $crawler = new Crawler();
  174. $crawler->addContent('<html><div class="foo"></div></html>', 'text/xml');
  175. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an XML string');
  176. $crawler = new Crawler();
  177. $crawler->addContent('foo bar', 'text/plain');
  178. $this->assertCount(0, $crawler, '->addContent() does nothing if the type is not (x|ht)ml');
  179. $crawler = new Crawler();
  180. $crawler->addContent('<html><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><span>中文</span></html>');
  181. $this->assertEquals('中文', $crawler->filterXPath('//span')->text(), '->addContent() guess wrong charset');
  182. }
  183. /**
  184. * @covers Symfony\Component\DomCrawler\Crawler::addDocument
  185. */
  186. public function testAddDocument()
  187. {
  188. $crawler = new Crawler();
  189. $crawler->addDocument($this->createDomDocument());
  190. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addDocument() adds nodes from a \DOMDocument');
  191. }
  192. /**
  193. * @covers Symfony\Component\DomCrawler\Crawler::addNodeList
  194. */
  195. public function testAddNodeList()
  196. {
  197. $crawler = new Crawler();
  198. $crawler->addNodeList($this->createNodeList());
  199. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addNodeList() adds nodes from a \DOMNodeList');
  200. }
  201. /**
  202. * @covers Symfony\Component\DomCrawler\Crawler::addNodes
  203. */
  204. public function testAddNodes()
  205. {
  206. foreach ($this->createNodeList() as $node) {
  207. $list[] = $node;
  208. }
  209. $crawler = new Crawler();
  210. $crawler->addNodes($list);
  211. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addNodes() adds nodes from an array of nodes');
  212. }
  213. /**
  214. * @covers Symfony\Component\DomCrawler\Crawler::addNode
  215. */
  216. public function testAddNode()
  217. {
  218. $crawler = new Crawler();
  219. $crawler->addNode($this->createNodeList()->item(0));
  220. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addNode() adds nodes from an \DOMNode');
  221. }
  222. public function testClear()
  223. {
  224. $crawler = new Crawler(new \DOMNode());
  225. $crawler->clear();
  226. $this->assertCount(0, $crawler, '->clear() removes all the nodes from the crawler');
  227. }
  228. public function testEq()
  229. {
  230. $crawler = $this->createTestCrawler()->filterXPath('//li');
  231. $this->assertNotSame($crawler, $crawler->eq(0), '->eq() returns a new instance of a crawler');
  232. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->eq() returns a new instance of a crawler');
  233. $this->assertEquals('Two', $crawler->eq(1)->text(), '->eq() returns the nth node of the list');
  234. $this->assertCount(0, $crawler->eq(100), '->eq() returns an empty crawler if the nth node does not exist');
  235. }
  236. public function testEach()
  237. {
  238. $data = $this->createTestCrawler()->filterXPath('//ul[1]/li')->each(function ($node, $i) {
  239. return $i.'-'.$node->text();
  240. });
  241. $this->assertEquals(array('0-One', '1-Two', '2-Three'), $data, '->each() executes an anonymous function on each node of the list');
  242. }
  243. public function testReduce()
  244. {
  245. $crawler = $this->createTestCrawler()->filterXPath('//ul[1]/li');
  246. $nodes = $crawler->reduce(function ($node, $i) {
  247. return $i == 1 ? false : true;
  248. });
  249. $this->assertNotSame($nodes, $crawler, '->reduce() returns a new instance of a crawler');
  250. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $nodes, '->reduce() returns a new instance of a crawler');
  251. $this->assertCount(2, $nodes, '->reduce() filters the nodes in the list');
  252. }
  253. public function testAttr()
  254. {
  255. $this->assertEquals('first', $this->createTestCrawler()->filterXPath('//li')->attr('class'), '->attr() returns the attribute of the first element of the node list');
  256. try {
  257. $this->createTestCrawler()->filterXPath('//ol')->attr('class');
  258. $this->fail('->attr() throws an \InvalidArgumentException if the node list is empty');
  259. } catch (\InvalidArgumentException $e) {
  260. $this->assertTrue(true, '->attr() throws an \InvalidArgumentException if the node list is empty');
  261. }
  262. }
  263. public function testText()
  264. {
  265. $this->assertEquals('One', $this->createTestCrawler()->filterXPath('//li')->text(), '->text() returns the node value of the first element of the node list');
  266. try {
  267. $this->createTestCrawler()->filterXPath('//ol')->text();
  268. $this->fail('->text() throws an \InvalidArgumentException if the node list is empty');
  269. } catch (\InvalidArgumentException $e) {
  270. $this->assertTrue(true, '->text() throws an \InvalidArgumentException if the node list is empty');
  271. }
  272. }
  273. public function testHtml()
  274. {
  275. $this->assertEquals('<img alt="Bar">', $this->createTestCrawler()->filterXPath('//a[5]')->html());
  276. $this->assertEquals('<input type="text" value="TextValue" name="TextName"><input type="submit" value="FooValue" name="FooName" id="FooId"><input type="button" value="BarValue" name="BarName" id="BarId"><button value="ButtonValue" name="ButtonName" id="ButtonId"></button>'
  277. , trim($this->createTestCrawler()->filterXPath('//form[@id="FooFormId"]')->html()));
  278. try {
  279. $this->createTestCrawler()->filterXPath('//ol')->html();
  280. $this->fail('->html() throws an \InvalidArgumentException if the node list is empty');
  281. } catch (\InvalidArgumentException $e) {
  282. $this->assertTrue(true, '->html() throws an \InvalidArgumentException if the node list is empty');
  283. }
  284. }
  285. public function testExtract()
  286. {
  287. $crawler = $this->createTestCrawler()->filterXPath('//ul[1]/li');
  288. $this->assertEquals(array('One', 'Two', 'Three'), $crawler->extract('_text'), '->extract() returns an array of extracted data from the node list');
  289. $this->assertEquals(array(array('One', 'first'), array('Two', ''), array('Three', '')), $crawler->extract(array('_text', 'class')), '->extract() returns an array of extracted data from the node list');
  290. $this->assertEquals(array(), $this->createTestCrawler()->filterXPath('//ol')->extract('_text'), '->extract() returns an empty array if the node list is empty');
  291. }
  292. /**
  293. * @covers Symfony\Component\DomCrawler\Crawler::filterXPath
  294. */
  295. public function testFilterXPath()
  296. {
  297. $crawler = $this->createTestCrawler();
  298. $this->assertNotSame($crawler, $crawler->filterXPath('//li'), '->filterXPath() returns a new instance of a crawler');
  299. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->filterXPath() returns a new instance of a crawler');
  300. $crawler = $this->createTestCrawler()->filterXPath('//ul');
  301. $this->assertCount(6, $crawler->filterXPath('//li'), '->filterXPath() filters the node list with the XPath expression');
  302. }
  303. /**
  304. * @covers Symfony\Component\DomCrawler\Crawler::filter
  305. */
  306. public function testFilter()
  307. {
  308. if (!class_exists('Symfony\Component\CssSelector\CssSelector')) {
  309. $this->markTestSkipped('The "CssSelector" component is not available');
  310. }
  311. $crawler = $this->createTestCrawler();
  312. $this->assertNotSame($crawler, $crawler->filter('li'), '->filter() returns a new instance of a crawler');
  313. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->filter() returns a new instance of a crawler');
  314. $crawler = $this->createTestCrawler()->filter('ul');
  315. $this->assertCount(6, $crawler->filter('li'), '->filter() filters the node list with the CSS selector');
  316. }
  317. public function testSelectLink()
  318. {
  319. $crawler = $this->createTestCrawler();
  320. $this->assertNotSame($crawler, $crawler->selectLink('Foo'), '->selectLink() returns a new instance of a crawler');
  321. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->selectLink() returns a new instance of a crawler');
  322. $this->assertCount(1, $crawler->selectLink('Fabien\'s Foo'), '->selectLink() selects links by the node values');
  323. $this->assertCount(1, $crawler->selectLink('Fabien\'s Bar'), '->selectLink() selects links by the alt attribute of a clickable image');
  324. $this->assertCount(2, $crawler->selectLink('Fabien"s Foo'), '->selectLink() selects links by the node values');
  325. $this->assertCount(2, $crawler->selectLink('Fabien"s Bar'), '->selectLink() selects links by the alt attribute of a clickable image');
  326. $this->assertCount(1, $crawler->selectLink('\' Fabien"s Foo'), '->selectLink() selects links by the node values');
  327. $this->assertCount(1, $crawler->selectLink('\' Fabien"s Bar'), '->selectLink() selects links by the alt attribute of a clickable image');
  328. $this->assertCount(4, $crawler->selectLink('Foo'), '->selectLink() selects links by the node values');
  329. $this->assertCount(4, $crawler->selectLink('Bar'), '->selectLink() selects links by the node values');
  330. }
  331. public function testSelectButton()
  332. {
  333. $crawler = $this->createTestCrawler();
  334. $this->assertNotSame($crawler, $crawler->selectButton('FooValue'), '->selectButton() returns a new instance of a crawler');
  335. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->selectButton() returns a new instance of a crawler');
  336. $this->assertEquals(1, $crawler->selectButton('FooValue')->count(), '->selectButton() selects buttons');
  337. $this->assertEquals(1, $crawler->selectButton('FooName')->count(), '->selectButton() selects buttons');
  338. $this->assertEquals(1, $crawler->selectButton('FooId')->count(), '->selectButton() selects buttons');
  339. $this->assertEquals(1, $crawler->selectButton('BarValue')->count(), '->selectButton() selects buttons');
  340. $this->assertEquals(1, $crawler->selectButton('BarName')->count(), '->selectButton() selects buttons');
  341. $this->assertEquals(1, $crawler->selectButton('BarId')->count(), '->selectButton() selects buttons');
  342. $this->assertEquals(1, $crawler->selectButton('FooBarValue')->count(), '->selectButton() selects buttons with form attribute too');
  343. $this->assertEquals(1, $crawler->selectButton('FooBarName')->count(), '->selectButton() selects buttons with form attribute too');
  344. }
  345. public function testLink()
  346. {
  347. $crawler = $this->createTestCrawler('http://example.com/bar/')->selectLink('Foo');
  348. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Link', $crawler->link(), '->link() returns a Link instance');
  349. $this->assertEquals('POST', $crawler->link('post')->getMethod(), '->link() takes a method as its argument');
  350. $crawler = $this->createTestCrawler('http://example.com/bar')->selectLink('GetLink');
  351. $this->assertEquals('http://example.com/bar?get=param', $crawler->link()->getUri(), '->link() returns a Link instance');
  352. try {
  353. $this->createTestCrawler()->filterXPath('//ol')->link();
  354. $this->fail('->link() throws an \InvalidArgumentException if the node list is empty');
  355. } catch (\InvalidArgumentException $e) {
  356. $this->assertTrue(true, '->link() throws an \InvalidArgumentException if the node list is empty');
  357. }
  358. }
  359. public function testLinks()
  360. {
  361. $crawler = $this->createTestCrawler('http://example.com/bar/')->selectLink('Foo');
  362. $this->assertInternalType('array', $crawler->links(), '->links() returns an array');
  363. $this->assertCount(4, $crawler->links(), '->links() returns an array');
  364. $links = $crawler->links();
  365. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Link', $links[0], '->links() returns an array of Link instances');
  366. $this->assertEquals(array(), $this->createTestCrawler()->filterXPath('//ol')->links(), '->links() returns an empty array if the node selection is empty');
  367. }
  368. public function testForm()
  369. {
  370. $testCrawler = $this->createTestCrawler('http://example.com/bar/');
  371. $crawler = $testCrawler->selectButton('FooValue');
  372. $crawler2 = $testCrawler->selectButton('FooBarValue');
  373. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Form', $crawler->form(), '->form() returns a Form instance');
  374. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Form', $crawler2->form(), '->form() returns a Form instance');
  375. $this->assertEquals($crawler->form()->getFormNode()->getAttribute('id'), $crawler2->form()->getFormNode()->getAttribute('id'), '->form() works on elements with form attribute');
  376. $this->assertEquals(array('FooName' => 'FooBar', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler->form(array('FooName' => 'FooBar'))->getValues(), '->form() takes an array of values to submit as its first argument');
  377. $this->assertEquals(array('FooName' => 'FooValue', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler->form()->getValues(), '->getValues() returns correct form values');
  378. $this->assertEquals(array('FooBarName' => 'FooBarValue', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler2->form()->getValues(), '->getValues() returns correct form values');
  379. try {
  380. $this->createTestCrawler()->filterXPath('//ol')->form();
  381. $this->fail('->form() throws an \InvalidArgumentException if the node list is empty');
  382. } catch (\InvalidArgumentException $e) {
  383. $this->assertTrue(true, '->form() throws an \InvalidArgumentException if the node list is empty');
  384. }
  385. }
  386. public function testLast()
  387. {
  388. $crawler = $this->createTestCrawler()->filterXPath('//ul[1]/li');
  389. $this->assertNotSame($crawler, $crawler->last(), '->last() returns a new instance of a crawler');
  390. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->last() returns a new instance of a crawler');
  391. $this->assertEquals('Three', $crawler->last()->text());
  392. }
  393. public function testFirst()
  394. {
  395. $crawler = $this->createTestCrawler()->filterXPath('//li');
  396. $this->assertNotSame($crawler, $crawler->first(), '->first() returns a new instance of a crawler');
  397. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->first() returns a new instance of a crawler');
  398. $this->assertEquals('One', $crawler->first()->text());
  399. }
  400. public function testSiblings()
  401. {
  402. $crawler = $this->createTestCrawler()->filterXPath('//li')->eq(1);
  403. $this->assertNotSame($crawler, $crawler->siblings(), '->siblings() returns a new instance of a crawler');
  404. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->siblings() returns a new instance of a crawler');
  405. $nodes = $crawler->siblings();
  406. $this->assertEquals(2, $nodes->count());
  407. $this->assertEquals('One', $nodes->eq(0)->text());
  408. $this->assertEquals('Three', $nodes->eq(1)->text());
  409. $nodes = $this->createTestCrawler()->filterXPath('//li')->eq(0)->siblings();
  410. $this->assertEquals(2, $nodes->count());
  411. $this->assertEquals('Two', $nodes->eq(0)->text());
  412. $this->assertEquals('Three', $nodes->eq(1)->text());
  413. try {
  414. $this->createTestCrawler()->filterXPath('//ol')->siblings();
  415. $this->fail('->siblings() throws an \InvalidArgumentException if the node list is empty');
  416. } catch (\InvalidArgumentException $e) {
  417. $this->assertTrue(true, '->siblings() throws an \InvalidArgumentException if the node list is empty');
  418. }
  419. }
  420. public function testNextAll()
  421. {
  422. $crawler = $this->createTestCrawler()->filterXPath('//li')->eq(1);
  423. $this->assertNotSame($crawler, $crawler->nextAll(), '->nextAll() returns a new instance of a crawler');
  424. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->nextAll() returns a new instance of a crawler');
  425. $nodes = $crawler->nextAll();
  426. $this->assertEquals(1, $nodes->count());
  427. $this->assertEquals('Three', $nodes->eq(0)->text());
  428. try {
  429. $this->createTestCrawler()->filterXPath('//ol')->nextAll();
  430. $this->fail('->nextAll() throws an \InvalidArgumentException if the node list is empty');
  431. } catch (\InvalidArgumentException $e) {
  432. $this->assertTrue(true, '->nextAll() throws an \InvalidArgumentException if the node list is empty');
  433. }
  434. }
  435. public function testPreviousAll()
  436. {
  437. $crawler = $this->createTestCrawler()->filterXPath('//li')->eq(2);
  438. $this->assertNotSame($crawler, $crawler->previousAll(), '->previousAll() returns a new instance of a crawler');
  439. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->previousAll() returns a new instance of a crawler');
  440. $nodes = $crawler->previousAll();
  441. $this->assertEquals(2, $nodes->count());
  442. $this->assertEquals('Two', $nodes->eq(0)->text());
  443. try {
  444. $this->createTestCrawler()->filterXPath('//ol')->previousAll();
  445. $this->fail('->previousAll() throws an \InvalidArgumentException if the node list is empty');
  446. } catch (\InvalidArgumentException $e) {
  447. $this->assertTrue(true, '->previousAll() throws an \InvalidArgumentException if the node list is empty');
  448. }
  449. }
  450. public function testChildren()
  451. {
  452. $crawler = $this->createTestCrawler()->filterXPath('//ul');
  453. $this->assertNotSame($crawler, $crawler->children(), '->children() returns a new instance of a crawler');
  454. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->children() returns a new instance of a crawler');
  455. $nodes = $crawler->children();
  456. $this->assertEquals(3, $nodes->count());
  457. $this->assertEquals('One', $nodes->eq(0)->text());
  458. $this->assertEquals('Two', $nodes->eq(1)->text());
  459. $this->assertEquals('Three', $nodes->eq(2)->text());
  460. try {
  461. $this->createTestCrawler()->filterXPath('//ol')->children();
  462. $this->fail('->children() throws an \InvalidArgumentException if the node list is empty');
  463. } catch (\InvalidArgumentException $e) {
  464. $this->assertTrue(true, '->children() throws an \InvalidArgumentException if the node list is empty');
  465. }
  466. try {
  467. $crawler = new Crawler('<p></p>');
  468. $crawler->filter('p')->children();
  469. $this->assertTrue(true, '->children() does not trigger a notice if the node has no children');
  470. } catch (\PHPUnit_Framework_Error_Notice $e) {
  471. $this->fail('->children() does not trigger a notice if the node has no children');
  472. }
  473. }
  474. public function testParents()
  475. {
  476. $crawler = $this->createTestCrawler()->filterXPath('//li[1]');
  477. $this->assertNotSame($crawler, $crawler->parents(), '->parents() returns a new instance of a crawler');
  478. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->parents() returns a new instance of a crawler');
  479. $nodes = $crawler->parents();
  480. $this->assertEquals(3, $nodes->count());
  481. $nodes = $this->createTestCrawler()->filterXPath('//html')->parents();
  482. $this->assertEquals(0, $nodes->count());
  483. try {
  484. $this->createTestCrawler()->filterXPath('//ol')->parents();
  485. $this->fail('->parents() throws an \InvalidArgumentException if the node list is empty');
  486. } catch (\InvalidArgumentException $e) {
  487. $this->assertTrue(true, '->parents() throws an \InvalidArgumentException if the node list is empty');
  488. }
  489. }
  490. public function testBaseTag()
  491. {
  492. $crawler = new Crawler('<html><base href="http://base.com"><a href="link"></a></html>');
  493. $this->assertEquals('http://base.com/link', $crawler->filterXPath('//a')->link()->getUri());
  494. $crawler = new Crawler('<html><base href="//base.com"><a href="link"></a></html>', 'https://domain.com');
  495. $this->assertEquals('https://base.com/link', $crawler->filterXPath('//a')->link()->getUri(), '<base> tag can use a schema-less url');
  496. $crawler = new Crawler('<html><base href="path/"><a href="link"></a></html>', 'https://domain.com');
  497. $this->assertEquals('https://domain.com/path/link', $crawler->filterXPath('//a')->link()->getUri(), '<base> tag can set a path');
  498. }
  499. public function createTestCrawler($uri = null)
  500. {
  501. $dom = new \DOMDocument();
  502. $dom->loadHTML('
  503. <html>
  504. <body>
  505. <a href="foo">Foo</a>
  506. <a href="/foo"> Fabien\'s Foo </a>
  507. <a href="/foo">Fabien"s Foo</a>
  508. <a href="/foo">\' Fabien"s Foo</a>
  509. <a href="/bar"><img alt="Bar"/></a>
  510. <a href="/bar"><img alt=" Fabien\'s Bar "/></a>
  511. <a href="/bar"><img alt="Fabien&quot;s Bar"/></a>
  512. <a href="/bar"><img alt="\' Fabien&quot;s Bar"/></a>
  513. <a href="?get=param">GetLink</a>
  514. <form action="foo" id="FooFormId">
  515. <input type="text" value="TextValue" name="TextName" />
  516. <input type="submit" value="FooValue" name="FooName" id="FooId" />
  517. <input type="button" value="BarValue" name="BarName" id="BarId" />
  518. <button value="ButtonValue" name="ButtonName" id="ButtonId" />
  519. </form>
  520. <input type="submit" value="FooBarValue" name="FooBarName" form="FooFormId" />
  521. <input type="text" value="FooTextValue" name="FooTextName" form="FooFormId" />
  522. <ul class="first">
  523. <li class="first">One</li>
  524. <li>Two</li>
  525. <li>Three</li>
  526. </ul>
  527. <ul>
  528. <li>One Bis</li>
  529. <li>Two Bis</li>
  530. <li>Three Bis</li>
  531. </ul>
  532. </body>
  533. </html>
  534. ');
  535. return new Crawler($dom, $uri);
  536. }
  537. protected function createDomDocument()
  538. {
  539. $dom = new \DOMDocument();
  540. $dom->loadXML('<html><div class="foo"></div></html>');
  541. return $dom;
  542. }
  543. protected function createNodeList()
  544. {
  545. $dom = new \DOMDocument();
  546. $dom->loadXML('<html><div class="foo"></div></html>');
  547. $domxpath = new \DOMXPath($dom);
  548. return $domxpath->query('//div');
  549. }
  550. }