CrawlerTest.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  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. }
  180. /**
  181. * @covers Symfony\Component\DomCrawler\Crawler::addDocument
  182. */
  183. public function testAddDocument()
  184. {
  185. $crawler = new Crawler();
  186. $crawler->addDocument($this->createDomDocument());
  187. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addDocument() adds nodes from a \DOMDocument');
  188. }
  189. /**
  190. * @covers Symfony\Component\DomCrawler\Crawler::addNodeList
  191. */
  192. public function testAddNodeList()
  193. {
  194. $crawler = new Crawler();
  195. $crawler->addNodeList($this->createNodeList());
  196. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addNodeList() adds nodes from a \DOMNodeList');
  197. }
  198. /**
  199. * @covers Symfony\Component\DomCrawler\Crawler::addNodes
  200. */
  201. public function testAddNodes()
  202. {
  203. foreach ($this->createNodeList() as $node) {
  204. $list[] = $node;
  205. }
  206. $crawler = new Crawler();
  207. $crawler->addNodes($list);
  208. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addNodes() adds nodes from an array of nodes');
  209. }
  210. /**
  211. * @covers Symfony\Component\DomCrawler\Crawler::addNode
  212. */
  213. public function testAddNode()
  214. {
  215. $crawler = new Crawler();
  216. $crawler->addNode($this->createNodeList()->item(0));
  217. $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addNode() adds nodes from an \DOMNode');
  218. }
  219. public function testClear()
  220. {
  221. $crawler = new Crawler(new \DOMNode());
  222. $crawler->clear();
  223. $this->assertCount(0, $crawler, '->clear() removes all the nodes from the crawler');
  224. }
  225. public function testEq()
  226. {
  227. $crawler = $this->createTestCrawler()->filterXPath('//li');
  228. $this->assertNotSame($crawler, $crawler->eq(0), '->eq() returns a new instance of a crawler');
  229. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->eq() returns a new instance of a crawler');
  230. $this->assertEquals('Two', $crawler->eq(1)->text(), '->eq() returns the nth node of the list');
  231. $this->assertCount(0, $crawler->eq(100), '->eq() returns an empty crawler if the nth node does not exist');
  232. }
  233. public function testEach()
  234. {
  235. $data = $this->createTestCrawler()->filterXPath('//ul[1]/li')->each(function ($node, $i) {
  236. return $i.'-'.$node->text();
  237. });
  238. $this->assertEquals(array('0-One', '1-Two', '2-Three'), $data, '->each() executes an anonymous function on each node of the list');
  239. }
  240. public function testReduce()
  241. {
  242. $crawler = $this->createTestCrawler()->filterXPath('//ul[1]/li');
  243. $nodes = $crawler->reduce(function ($node, $i) {
  244. return $i == 1 ? false : true;
  245. });
  246. $this->assertNotSame($nodes, $crawler, '->reduce() returns a new instance of a crawler');
  247. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $nodes, '->reduce() returns a new instance of a crawler');
  248. $this->assertCount(2, $nodes, '->reduce() filters the nodes in the list');
  249. }
  250. public function testAttr()
  251. {
  252. $this->assertEquals('first', $this->createTestCrawler()->filterXPath('//li')->attr('class'), '->attr() returns the attribute of the first element of the node list');
  253. try {
  254. $this->createTestCrawler()->filterXPath('//ol')->attr('class');
  255. $this->fail('->attr() throws an \InvalidArgumentException if the node list is empty');
  256. } catch (\InvalidArgumentException $e) {
  257. $this->assertTrue(true, '->attr() throws an \InvalidArgumentException if the node list is empty');
  258. }
  259. }
  260. public function testText()
  261. {
  262. $this->assertEquals('One', $this->createTestCrawler()->filterXPath('//li')->text(), '->text() returns the node value of the first element of the node list');
  263. try {
  264. $this->createTestCrawler()->filterXPath('//ol')->text();
  265. $this->fail('->text() throws an \InvalidArgumentException if the node list is empty');
  266. } catch (\InvalidArgumentException $e) {
  267. $this->assertTrue(true, '->text() throws an \InvalidArgumentException if the node list is empty');
  268. }
  269. }
  270. public function testHtml()
  271. {
  272. $this->assertEquals('<img alt="Bar">', $this->createTestCrawler()->filterXPath('//a[5]')->html());
  273. $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>'
  274. , trim($this->createTestCrawler()->filterXPath('//form[@id="FooFormId"]')->html()));
  275. try {
  276. $this->createTestCrawler()->filterXPath('//ol')->html();
  277. $this->fail('->html() throws an \InvalidArgumentException if the node list is empty');
  278. } catch (\InvalidArgumentException $e) {
  279. $this->assertTrue(true, '->html() throws an \InvalidArgumentException if the node list is empty');
  280. }
  281. }
  282. public function testExtract()
  283. {
  284. $crawler = $this->createTestCrawler()->filterXPath('//ul[1]/li');
  285. $this->assertEquals(array('One', 'Two', 'Three'), $crawler->extract('_text'), '->extract() returns an array of extracted data from the node list');
  286. $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');
  287. $this->assertEquals(array(), $this->createTestCrawler()->filterXPath('//ol')->extract('_text'), '->extract() returns an empty array if the node list is empty');
  288. }
  289. /**
  290. * @covers Symfony\Component\DomCrawler\Crawler::filterXPath
  291. */
  292. public function testFilterXPath()
  293. {
  294. $crawler = $this->createTestCrawler();
  295. $this->assertNotSame($crawler, $crawler->filterXPath('//li'), '->filterXPath() returns a new instance of a crawler');
  296. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->filterXPath() returns a new instance of a crawler');
  297. $crawler = $this->createTestCrawler()->filterXPath('//ul');
  298. $this->assertCount(6, $crawler->filterXPath('//li'), '->filterXPath() filters the node list with the XPath expression');
  299. }
  300. /**
  301. * @covers Symfony\Component\DomCrawler\Crawler::filter
  302. */
  303. public function testFilter()
  304. {
  305. if (!class_exists('Symfony\Component\CssSelector\CssSelector')) {
  306. $this->markTestSkipped('The "CssSelector" component is not available');
  307. }
  308. $crawler = $this->createTestCrawler();
  309. $this->assertNotSame($crawler, $crawler->filter('li'), '->filter() returns a new instance of a crawler');
  310. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->filter() returns a new instance of a crawler');
  311. $crawler = $this->createTestCrawler()->filter('ul');
  312. $this->assertCount(6, $crawler->filter('li'), '->filter() filters the node list with the CSS selector');
  313. }
  314. public function testSelectLink()
  315. {
  316. $crawler = $this->createTestCrawler();
  317. $this->assertNotSame($crawler, $crawler->selectLink('Foo'), '->selectLink() returns a new instance of a crawler');
  318. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->selectLink() returns a new instance of a crawler');
  319. $this->assertCount(1, $crawler->selectLink('Fabien\'s Foo'), '->selectLink() selects links by the node values');
  320. $this->assertCount(1, $crawler->selectLink('Fabien\'s Bar'), '->selectLink() selects links by the alt attribute of a clickable image');
  321. $this->assertCount(2, $crawler->selectLink('Fabien"s Foo'), '->selectLink() selects links by the node values');
  322. $this->assertCount(2, $crawler->selectLink('Fabien"s Bar'), '->selectLink() selects links by the alt attribute of a clickable image');
  323. $this->assertCount(1, $crawler->selectLink('\' Fabien"s Foo'), '->selectLink() selects links by the node values');
  324. $this->assertCount(1, $crawler->selectLink('\' Fabien"s Bar'), '->selectLink() selects links by the alt attribute of a clickable image');
  325. $this->assertCount(4, $crawler->selectLink('Foo'), '->selectLink() selects links by the node values');
  326. $this->assertCount(4, $crawler->selectLink('Bar'), '->selectLink() selects links by the node values');
  327. }
  328. public function testSelectButton()
  329. {
  330. $crawler = $this->createTestCrawler();
  331. $this->assertNotSame($crawler, $crawler->selectButton('FooValue'), '->selectButton() returns a new instance of a crawler');
  332. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->selectButton() returns a new instance of a crawler');
  333. $this->assertEquals(1, $crawler->selectButton('FooValue')->count(), '->selectButton() selects buttons');
  334. $this->assertEquals(1, $crawler->selectButton('FooName')->count(), '->selectButton() selects buttons');
  335. $this->assertEquals(1, $crawler->selectButton('FooId')->count(), '->selectButton() selects buttons');
  336. $this->assertEquals(1, $crawler->selectButton('BarValue')->count(), '->selectButton() selects buttons');
  337. $this->assertEquals(1, $crawler->selectButton('BarName')->count(), '->selectButton() selects buttons');
  338. $this->assertEquals(1, $crawler->selectButton('BarId')->count(), '->selectButton() selects buttons');
  339. $this->assertEquals(1, $crawler->selectButton('FooBarValue')->count(), '->selectButton() selects buttons with form attribute too');
  340. $this->assertEquals(1, $crawler->selectButton('FooBarName')->count(), '->selectButton() selects buttons with form attribute too');
  341. }
  342. public function testLink()
  343. {
  344. $crawler = $this->createTestCrawler('http://example.com/bar/')->selectLink('Foo');
  345. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Link', $crawler->link(), '->link() returns a Link instance');
  346. $this->assertEquals('POST', $crawler->link('post')->getMethod(), '->link() takes a method as its argument');
  347. $crawler = $this->createTestCrawler('http://example.com/bar')->selectLink('GetLink');
  348. $this->assertEquals('http://example.com/bar?get=param', $crawler->link()->getUri(), '->link() returns a Link instance');
  349. try {
  350. $this->createTestCrawler()->filterXPath('//ol')->link();
  351. $this->fail('->link() throws an \InvalidArgumentException if the node list is empty');
  352. } catch (\InvalidArgumentException $e) {
  353. $this->assertTrue(true, '->link() throws an \InvalidArgumentException if the node list is empty');
  354. }
  355. }
  356. public function testLinks()
  357. {
  358. $crawler = $this->createTestCrawler('http://example.com/bar/')->selectLink('Foo');
  359. $this->assertInternalType('array', $crawler->links(), '->links() returns an array');
  360. $this->assertCount(4, $crawler->links(), '->links() returns an array');
  361. $links = $crawler->links();
  362. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Link', $links[0], '->links() returns an array of Link instances');
  363. $this->assertEquals(array(), $this->createTestCrawler()->filterXPath('//ol')->links(), '->links() returns an empty array if the node selection is empty');
  364. }
  365. public function testForm()
  366. {
  367. $testCrawler = $this->createTestCrawler('http://example.com/bar/');
  368. $crawler = $testCrawler->selectButton('FooValue');
  369. $crawler2 = $testCrawler->selectButton('FooBarValue');
  370. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Form', $crawler->form(), '->form() returns a Form instance');
  371. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Form', $crawler2->form(), '->form() returns a Form instance');
  372. $this->assertEquals($crawler->form()->getFormNode()->getAttribute('id'), $crawler2->form()->getFormNode()->getAttribute('id'), '->form() works on elements with form attribute');
  373. $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');
  374. $this->assertEquals(array('FooName' => 'FooValue', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler->form()->getValues(), '->form() takes an array of values to submit as its first argument');
  375. $this->assertEquals(array('FooBarName' => 'FooBarValue', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler2->form()->getValues(), '->form() takes an array of values to submit as its first argument');
  376. try {
  377. $this->createTestCrawler()->filterXPath('//ol')->form();
  378. $this->fail('->form() throws an \InvalidArgumentException if the node list is empty');
  379. } catch (\InvalidArgumentException $e) {
  380. $this->assertTrue(true, '->form() throws an \InvalidArgumentException if the node list is empty');
  381. }
  382. }
  383. public function testLast()
  384. {
  385. $crawler = $this->createTestCrawler()->filterXPath('//ul[1]/li');
  386. $this->assertNotSame($crawler, $crawler->last(), '->last() returns a new instance of a crawler');
  387. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->last() returns a new instance of a crawler');
  388. $this->assertEquals('Three', $crawler->last()->text());
  389. }
  390. public function testFirst()
  391. {
  392. $crawler = $this->createTestCrawler()->filterXPath('//li');
  393. $this->assertNotSame($crawler, $crawler->first(), '->first() returns a new instance of a crawler');
  394. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->first() returns a new instance of a crawler');
  395. $this->assertEquals('One', $crawler->first()->text());
  396. }
  397. public function testSiblings()
  398. {
  399. $crawler = $this->createTestCrawler()->filterXPath('//li')->eq(1);
  400. $this->assertNotSame($crawler, $crawler->siblings(), '->siblings() returns a new instance of a crawler');
  401. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->siblings() returns a new instance of a crawler');
  402. $nodes = $crawler->siblings();
  403. $this->assertEquals(2, $nodes->count());
  404. $this->assertEquals('One', $nodes->eq(0)->text());
  405. $this->assertEquals('Three', $nodes->eq(1)->text());
  406. $nodes = $this->createTestCrawler()->filterXPath('//li')->eq(0)->siblings();
  407. $this->assertEquals(2, $nodes->count());
  408. $this->assertEquals('Two', $nodes->eq(0)->text());
  409. $this->assertEquals('Three', $nodes->eq(1)->text());
  410. try {
  411. $this->createTestCrawler()->filterXPath('//ol')->siblings();
  412. $this->fail('->siblings() throws an \InvalidArgumentException if the node list is empty');
  413. } catch (\InvalidArgumentException $e) {
  414. $this->assertTrue(true, '->siblings() throws an \InvalidArgumentException if the node list is empty');
  415. }
  416. }
  417. public function testNextAll()
  418. {
  419. $crawler = $this->createTestCrawler()->filterXPath('//li')->eq(1);
  420. $this->assertNotSame($crawler, $crawler->nextAll(), '->nextAll() returns a new instance of a crawler');
  421. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->nextAll() returns a new instance of a crawler');
  422. $nodes = $crawler->nextAll();
  423. $this->assertEquals(1, $nodes->count());
  424. $this->assertEquals('Three', $nodes->eq(0)->text());
  425. try {
  426. $this->createTestCrawler()->filterXPath('//ol')->nextAll();
  427. $this->fail('->nextAll() throws an \InvalidArgumentException if the node list is empty');
  428. } catch (\InvalidArgumentException $e) {
  429. $this->assertTrue(true, '->nextAll() throws an \InvalidArgumentException if the node list is empty');
  430. }
  431. }
  432. public function testPreviousAll()
  433. {
  434. $crawler = $this->createTestCrawler()->filterXPath('//li')->eq(2);
  435. $this->assertNotSame($crawler, $crawler->previousAll(), '->previousAll() returns a new instance of a crawler');
  436. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->previousAll() returns a new instance of a crawler');
  437. $nodes = $crawler->previousAll();
  438. $this->assertEquals(2, $nodes->count());
  439. $this->assertEquals('Two', $nodes->eq(0)->text());
  440. try {
  441. $this->createTestCrawler()->filterXPath('//ol')->previousAll();
  442. $this->fail('->previousAll() throws an \InvalidArgumentException if the node list is empty');
  443. } catch (\InvalidArgumentException $e) {
  444. $this->assertTrue(true, '->previousAll() throws an \InvalidArgumentException if the node list is empty');
  445. }
  446. }
  447. public function testChildren()
  448. {
  449. $crawler = $this->createTestCrawler()->filterXPath('//ul');
  450. $this->assertNotSame($crawler, $crawler->children(), '->children() returns a new instance of a crawler');
  451. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->children() returns a new instance of a crawler');
  452. $nodes = $crawler->children();
  453. $this->assertEquals(3, $nodes->count());
  454. $this->assertEquals('One', $nodes->eq(0)->text());
  455. $this->assertEquals('Two', $nodes->eq(1)->text());
  456. $this->assertEquals('Three', $nodes->eq(2)->text());
  457. try {
  458. $this->createTestCrawler()->filterXPath('//ol')->children();
  459. $this->fail('->children() throws an \InvalidArgumentException if the node list is empty');
  460. } catch (\InvalidArgumentException $e) {
  461. $this->assertTrue(true, '->children() throws an \InvalidArgumentException if the node list is empty');
  462. }
  463. try {
  464. $crawler = new Crawler('<p></p>');
  465. $crawler->filter('p')->children();
  466. $this->assertTrue(true, '->children() does not trigger a notice if the node has no children');
  467. } catch (\PHPUnit_Framework_Error_Notice $e) {
  468. $this->fail('->children() does not trigger a notice if the node has no children');
  469. }
  470. }
  471. public function testParents()
  472. {
  473. $crawler = $this->createTestCrawler()->filterXPath('//li[1]');
  474. $this->assertNotSame($crawler, $crawler->parents(), '->parents() returns a new instance of a crawler');
  475. $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Crawler', $crawler, '->parents() returns a new instance of a crawler');
  476. $nodes = $crawler->parents();
  477. $this->assertEquals(3, $nodes->count());
  478. $nodes = $this->createTestCrawler()->filterXPath('//html')->parents();
  479. $this->assertEquals(0, $nodes->count());
  480. try {
  481. $this->createTestCrawler()->filterXPath('//ol')->parents();
  482. $this->fail('->parents() throws an \InvalidArgumentException if the node list is empty');
  483. } catch (\InvalidArgumentException $e) {
  484. $this->assertTrue(true, '->parents() throws an \InvalidArgumentException if the node list is empty');
  485. }
  486. }
  487. public function testBaseTag()
  488. {
  489. $crawler = new Crawler('<html><base href="http://base.com"><a href="link"></a></html>');
  490. $this->assertEquals('http://base.com/link', $crawler->filterXPath('//a')->link()->getUri());
  491. $crawler = new Crawler('<html><base href="//base.com"><a href="link"></a></html>', 'https://domain.com');
  492. $this->assertEquals('https://base.com/link', $crawler->filterXPath('//a')->link()->getUri(), '<base> tag can use a schema-less url');
  493. $crawler = new Crawler('<html><base href="path/"><a href="link"></a></html>', 'https://domain.com');
  494. $this->assertEquals('https://domain.com/path/link', $crawler->filterXPath('//a')->link()->getUri(), '<base> tag can set a path');
  495. }
  496. public function createTestCrawler($uri = null)
  497. {
  498. $dom = new \DOMDocument();
  499. $dom->loadHTML('
  500. <html>
  501. <body>
  502. <a href="foo">Foo</a>
  503. <a href="/foo"> Fabien\'s Foo </a>
  504. <a href="/foo">Fabien"s Foo</a>
  505. <a href="/foo">\' Fabien"s Foo</a>
  506. <a href="/bar"><img alt="Bar"/></a>
  507. <a href="/bar"><img alt=" Fabien\'s Bar "/></a>
  508. <a href="/bar"><img alt="Fabien&quot;s Bar"/></a>
  509. <a href="/bar"><img alt="\' Fabien&quot;s Bar"/></a>
  510. <a href="?get=param">GetLink</a>
  511. <form action="foo" id="FooFormId">
  512. <input type="text" value="TextValue" name="TextName" />
  513. <input type="submit" value="FooValue" name="FooName" id="FooId" />
  514. <input type="button" value="BarValue" name="BarName" id="BarId" />
  515. <button value="ButtonValue" name="ButtonName" id="ButtonId" />
  516. </form>
  517. <input type="submit" value="FooBarValue" name="FooBarName" form="FooFormId" />
  518. <input type="text" value="FooTextValue" name="FooTextName" form="FooFormId" />
  519. <ul class="first">
  520. <li class="first">One</li>
  521. <li>Two</li>
  522. <li>Three</li>
  523. </ul>
  524. <ul>
  525. <li>One Bis</li>
  526. <li>Two Bis</li>
  527. <li>Three Bis</li>
  528. </ul>
  529. </body>
  530. </html>
  531. ');
  532. return new Crawler($dom, $uri);
  533. }
  534. protected function createDomDocument()
  535. {
  536. $dom = new \DOMDocument();
  537. $dom->loadXML('<html><div class="foo"></div></html>');
  538. return $dom;
  539. }
  540. protected function createNodeList()
  541. {
  542. $dom = new \DOMDocument();
  543. $dom->loadXML('<html><div class="foo"></div></html>');
  544. $domxpath = new \DOMXPath($dom);
  545. return $domxpath->query('//div');
  546. }
  547. }