ElementTest.php 67 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255
  1. <?php
  2. declare(strict_types=1);
  3. namespace DiDom\Tests;
  4. use DiDom\Document;
  5. use DiDom\Element;
  6. use DiDom\Query;
  7. use DOMCdataSection;
  8. use DOMComment;
  9. use DOMDocument;
  10. use DOMElement;
  11. use DOMText;
  12. use LogicException;
  13. use InvalidArgumentException;
  14. use RuntimeException;
  15. class ElementTest extends TestCase
  16. {
  17. public function testConstructorWithNullTagName()
  18. {
  19. $this->expectException(InvalidArgumentException::class);
  20. new Element(null);
  21. }
  22. public function testConstructorWithInvalidTagNameType()
  23. {
  24. $this->expectException(InvalidArgumentException::class);
  25. new Element([]);
  26. }
  27. public function testConstructorWithInvalidObject()
  28. {
  29. $this->expectException(InvalidArgumentException::class);
  30. new Element((object) []);
  31. }
  32. public function testConstructorWithInvalidValue()
  33. {
  34. $this->expectException(InvalidArgumentException::class);
  35. new Element('span', []);
  36. }
  37. public function testConstructor()
  38. {
  39. $element = new Element('input', null, ['name' => 'username', 'value' => 'John']);
  40. $this->assertEquals('input', $element->getNode()->tagName);
  41. $this->assertEquals('username', $element->getNode()->getAttribute('name'));
  42. $this->assertEquals('John', $element->getNode()->getAttribute('value'));
  43. // create from DOMElement
  44. $node = new DOMElement('span', 'Foo');
  45. $element = new Element($node);
  46. $this->assertEquals($node, $element->getNode());
  47. // create from DOMText
  48. $node = new DOMText('Foo');
  49. $element = new Element($node);
  50. $this->assertEquals($node, $element->getNode());
  51. // create from DOMComment
  52. $node = new DOMComment('Foo');
  53. $element = new Element($node);
  54. $this->assertEquals($node, $element->getNode());
  55. }
  56. public function testCreate()
  57. {
  58. $element = Element::create('span', 'Foo', ['class' => 'bar']);
  59. $this->assertEquals('span', $element->getNode()->tagName);
  60. $this->assertEquals('Foo', $element->text());
  61. $this->assertEquals(['class' => 'bar'], $element->attributes());
  62. }
  63. public function testCreateBySelector()
  64. {
  65. $element = Element::createBySelector('li.item.active', 'Foo', ['data-id' => 1]);
  66. $this->assertEquals('li', $element->getNode()->tagName);
  67. $this->assertEquals('Foo', $element->text());
  68. $this->assertEquals(['class' => 'item active', 'data-id' => 1], $element->attributes());
  69. }
  70. public function testTagName()
  71. {
  72. $element = new Element(new DOMElement('div'));
  73. $this->assertEquals('div', $element->tagName());
  74. }
  75. public function testPrependChildWithInvalidArgument()
  76. {
  77. $this->expectException(InvalidArgumentException::class);
  78. $element = new Element('span', 'hello');
  79. $element->prependChild('foo');
  80. }
  81. public function testPrependChildWithoutParentNode()
  82. {
  83. $this->expectException(LogicException::class);
  84. $this->expectExceptionMessage('Can not prepend a child to element without the owner document.');
  85. $element = new Element(new DOMElement('div'));
  86. $element->prependChild(new Element('div'));
  87. }
  88. public function testPrependChild()
  89. {
  90. $list = new Element('ul');
  91. $this->assertEquals(0, $list->getNode()->childNodes->length);
  92. $item = new Element('li', 'bar');
  93. $prependedChild = $list->prependChild($item);
  94. $this->assertEquals(1, $list->getNode()->childNodes->length);
  95. $this->assertInstanceOf('DiDom\Element', $prependedChild);
  96. $this->assertEquals('bar', $prependedChild->getNode()->textContent);
  97. $item = new Element('li', 'foo');
  98. $prependedChild = $list->prependChild($item);
  99. $this->assertEquals(2, $list->getNode()->childNodes->length);
  100. $this->assertInstanceOf('DiDom\Element', $prependedChild);
  101. $this->assertEquals('foo', $prependedChild->getNode()->textContent);
  102. $this->assertEquals('foo', $list->getNode()->childNodes->item(0)->textContent);
  103. $this->assertEquals('bar', $list->getNode()->childNodes->item(1)->textContent);
  104. }
  105. public function testPrependChildWithArrayOfNodes()
  106. {
  107. $list = new Element('ul');
  108. $prependedChild = $list->prependChild(new Element('li', 'foo'));
  109. $this->assertEquals(1, $list->getNode()->childNodes->length);
  110. $this->assertInstanceOf('DiDom\Element', $prependedChild);
  111. $this->assertEquals('foo', $prependedChild->getNode()->textContent);
  112. $items = [];
  113. $items[] = new Element('li', 'bar');
  114. $items[] = new Element('li', 'baz');
  115. $appendedChildren = $list->prependChild($items);
  116. $this->assertCount(2, $appendedChildren);
  117. $this->assertEquals(3, $list->getNode()->childNodes->length);
  118. foreach ($appendedChildren as $appendedChild) {
  119. $this->assertInstanceOf('DiDom\Element', $appendedChild);
  120. }
  121. foreach (['bar', 'baz', 'foo'] as $index => $value) {
  122. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  123. }
  124. }
  125. public function testPrependDocumentFragment()
  126. {
  127. $xml = '
  128. <list>
  129. <item>Foo</item>
  130. <item>Bar</item>
  131. <item>Baz</item>
  132. </list>
  133. ';
  134. $document = new Document();
  135. $document->loadXml($xml);
  136. $fragmentXml = '
  137. <item>Qux</item>
  138. <item>Quux</item>
  139. <item>Quuz</item>
  140. ';
  141. $documentFragment = $document->createDocumentFragment();
  142. $documentFragment->appendXml($fragmentXml);
  143. $document->first('list')->prependChild($documentFragment);
  144. $expectedContent = ['Qux', 'Quux', 'Quuz', 'Foo', 'Bar', 'Baz'];
  145. foreach ($document->find('item') as $index => $childNode) {
  146. $this->assertEquals('item', $childNode->getNode()->tagName);
  147. $this->assertEquals($expectedContent[$index], $childNode->text());
  148. }
  149. }
  150. public function testAppendChildWithInvalidArgument()
  151. {
  152. $this->expectException(InvalidArgumentException::class);
  153. $element = new Element('span', 'hello');
  154. $element->appendChild('foo');
  155. }
  156. public function testAppendChildWithoutParentNode()
  157. {
  158. $this->expectException(LogicException::class);
  159. $this->expectExceptionMessage('Can not append a child to element without the owner document');
  160. $element = new Element(new DOMElement('div'));
  161. $element->appendChild(new Element('div'));
  162. }
  163. public function testAppendChild()
  164. {
  165. $list = new Element('ul');
  166. $this->assertEquals(0, $list->getNode()->childNodes->length);
  167. $item = new Element('li', 'foo');
  168. $appendedChild = $list->appendChild($item);
  169. $this->assertEquals(1, $list->getNode()->childNodes->length);
  170. $this->assertInstanceOf('DiDom\Element', $appendedChild);
  171. $this->assertEquals('foo', $appendedChild->getNode()->textContent);
  172. $item = new Element('li', 'bar');
  173. $appendedChild = $list->appendChild($item);
  174. $this->assertEquals(2, $list->getNode()->childNodes->length);
  175. $this->assertInstanceOf('DiDom\Element', $appendedChild);
  176. $this->assertEquals('bar', $appendedChild->getNode()->textContent);
  177. $this->assertEquals('foo', $list->getNode()->childNodes->item(0)->textContent);
  178. $this->assertEquals('bar', $list->getNode()->childNodes->item(1)->textContent);
  179. }
  180. public function testAppendChildWithArray()
  181. {
  182. $list = new Element('ul');
  183. $appendedChild = $list->appendChild(new Element('li', 'foo'));
  184. $this->assertEquals(1, $list->getNode()->childNodes->length);
  185. $this->assertInstanceOf('DiDom\Element', $appendedChild);
  186. $this->assertEquals('foo', $appendedChild->getNode()->textContent);
  187. $items = [];
  188. $items[] = new Element('li', 'bar');
  189. $items[] = new Element('li', 'baz');
  190. $appendedChildren = $list->appendChild($items);
  191. $this->assertCount(2, $appendedChildren);
  192. $this->assertEquals(3, $list->getNode()->childNodes->length);
  193. foreach ($appendedChildren as $appendedChild) {
  194. $this->assertInstanceOf('DiDom\Element', $appendedChild);
  195. }
  196. foreach (['foo', 'bar', 'baz'] as $index => $value) {
  197. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  198. }
  199. }
  200. public function testAppendDocumentFragment()
  201. {
  202. $xml = '
  203. <list>
  204. <item>Foo</item>
  205. <item>Bar</item>
  206. <item>Baz</item>
  207. </list>
  208. ';
  209. $document = new Document();
  210. $document->loadXml($xml);
  211. $fragmentXml = '
  212. <item>Qux</item>
  213. <item>Quux</item>
  214. <item>Quuz</item>
  215. ';
  216. $documentFragment = $document->createDocumentFragment();
  217. $documentFragment->appendXml($fragmentXml);
  218. $document->first('list')->appendChild($documentFragment);
  219. $expectedContent = ['Foo', 'Bar', 'Baz', 'Qux', 'Quux', 'Quuz'];
  220. foreach ($document->find('item') as $index => $childNode) {
  221. $this->assertEquals('item', $childNode->getNode()->tagName);
  222. $this->assertEquals($expectedContent[$index], $childNode->text());
  223. }
  224. }
  225. public function testInsertBeforeWithInvalidNodeArgument()
  226. {
  227. $this->expectException(InvalidArgumentException::class);
  228. $this->expectExceptionMessage('Argument 1 passed to DiDom\Node::insertBefore must be an instance of DiDom\Node or DOMNode, string given');
  229. $list = new Element('ul');
  230. $list->insertBefore('foo');
  231. }
  232. public function testInsertBeforeWithInvalidReferenceNodeArgument()
  233. {
  234. $this->expectException(InvalidArgumentException::class);
  235. $this->expectExceptionMessage('Argument 2 passed to DiDom\Node::insertBefore must be an instance of DiDom\Node or DOMNode, string given');
  236. $list = new Element('ul');
  237. $list->insertBefore(new Element('li', 'foo'), 'foo');
  238. }
  239. public function testInsertBeforeWithoutParentNode()
  240. {
  241. $this->expectException(LogicException::class);
  242. $this->expectExceptionMessage('Can not insert a child to an element without the owner document');
  243. $list = new Element(new DOMElement('ul'));
  244. $list->insertBefore(new Element('li', 'foo'));
  245. }
  246. public function testInsertBefore()
  247. {
  248. $list = new Element('ul');
  249. $insertedNode = $list->insertBefore(new Element('li', 'baz'));
  250. $this->assertInstanceOf('DiDom\Element', $insertedNode);
  251. $this->assertEquals('baz', $insertedNode->getNode()->textContent);
  252. foreach (['baz'] as $index => $value) {
  253. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  254. }
  255. $list->insertBefore(new Element('li', 'foo'), $list->getNode()->childNodes->item(0));
  256. foreach (['foo', 'baz'] as $index => $value) {
  257. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  258. }
  259. $list->insertBefore(new Element('li', 'bar'), $list->getNode()->childNodes->item(1));
  260. foreach (['foo', 'bar', 'baz'] as $index => $value) {
  261. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  262. }
  263. // without the reference node
  264. $list->insertBefore(new Element('li', 'qux'));
  265. foreach (['foo', 'bar', 'baz', 'qux'] as $index => $value) {
  266. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  267. }
  268. }
  269. public function testInsertAfterWithInvalidNodeArgument()
  270. {
  271. $this->expectException(InvalidArgumentException::class);
  272. $this->expectExceptionMessage('Argument 1 passed to DiDom\Node::insertBefore must be an instance of DiDom\Node or DOMNode, string given');
  273. $list = new Element('ul');
  274. $list->insertAfter('foo');
  275. }
  276. public function testInsertAfterWithInvalidReferenceNodeArgument()
  277. {
  278. $this->expectException(InvalidArgumentException::class);
  279. $this->expectExceptionMessage('Argument 2 passed to DiDom\Node::insertAfter must be an instance of DiDom\Node or DOMNode, string given');
  280. $list = new Element('ul');
  281. $list->insertAfter(new Element('li', 'foo'), 'foo');
  282. }
  283. public function testInsertAfterWithoutParentNode()
  284. {
  285. $this->expectException(LogicException::class);
  286. $this->expectExceptionMessage('Can not insert a child to an element without the owner document');
  287. $list = new Element(new DOMElement('ul'));
  288. $list->insertAfter(new Element('li', 'foo'));
  289. }
  290. public function testInsertAfter()
  291. {
  292. $list = new Element('ul');
  293. $insertedNode = $list->insertAfter(new Element('li', 'foo'));
  294. $this->assertInstanceOf('DiDom\Element', $insertedNode);
  295. $this->assertEquals('foo', $insertedNode->getNode()->textContent);
  296. foreach (['foo'] as $index => $value) {
  297. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  298. }
  299. $list->insertAfter(new Element('li', 'baz'), $list->getNode()->childNodes->item(0));
  300. foreach (['foo', 'baz'] as $index => $value) {
  301. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  302. }
  303. $list->insertAfter(new Element('li', 'bar'), $list->getNode()->childNodes->item(0));
  304. foreach (['foo', 'bar', 'baz'] as $index => $value) {
  305. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  306. }
  307. // without the reference node
  308. $list->insertAfter(new Element('li', 'qux'));
  309. foreach (['foo', 'bar', 'baz', 'qux'] as $index => $value) {
  310. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  311. }
  312. }
  313. public function testInsertSiblingBeforeWithInvalidNodeArgument()
  314. {
  315. $this->expectException(InvalidArgumentException::class);
  316. $this->expectExceptionMessage('Argument 1 passed to DiDom\Node::insertSiblingBefore must be an instance of DiDom\Node or DOMNode, string given');
  317. $list = new Element('ul');
  318. $item = $list->appendChild(new Element('li', 'foo'));
  319. $item->insertSiblingBefore('foo');
  320. }
  321. public function testInsertSiblingBeforeWithoutParentNode()
  322. {
  323. $this->expectException(LogicException::class);
  324. $this->expectExceptionMessage('Can not insert a child to an element without the owner document');
  325. $item = new Element(new DOMElement('li', 'foo'));
  326. $item->insertSiblingBefore(new Element('li', 'bar'));
  327. }
  328. public function testInsertSiblingBefore()
  329. {
  330. $list = new Element('ul');
  331. $insertedNode = $list->appendChild(new Element('li', 'baz'));
  332. $this->assertInstanceOf('DiDom\Element', $insertedNode);
  333. $this->assertEquals('baz', $insertedNode->getNode()->textContent);
  334. foreach (['baz'] as $index => $value) {
  335. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  336. }
  337. $insertedNode->insertSiblingBefore(new Element('li', 'foo'));
  338. foreach (['foo', 'baz'] as $index => $value) {
  339. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  340. }
  341. $insertedNode->insertSiblingBefore(new Element('li', 'bar'));
  342. foreach (['foo', 'bar', 'baz'] as $index => $value) {
  343. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  344. }
  345. }
  346. public function testInsertSiblingAfterWithInvalidNodeArgument()
  347. {
  348. $this->expectException(InvalidArgumentException::class);
  349. $this->expectExceptionMessage('Argument 1 passed to DiDom\Node::appendChild must be an instance of DiDom\Node or DOMNode, string given');
  350. $list = new Element('ul');
  351. $item = $list->appendChild(new Element('li', 'foo'));
  352. $item->insertSiblingAfter('foo');
  353. }
  354. public function testInsertSiblingAfterWithoutParentNode()
  355. {
  356. $this->expectException(LogicException::class);
  357. $this->expectExceptionMessage('Can not insert a child to an element without the owner document');
  358. $item = new Element(new DOMElement('li', 'foo'));
  359. $item->insertSiblingAfter(new Element('li', 'bar'));
  360. }
  361. public function testInsertSiblingAfter()
  362. {
  363. $list = new Element('ul');
  364. $insertedNode = $list->appendChild(new Element('li', 'foo'));
  365. $this->assertInstanceOf('DiDom\Element', $insertedNode);
  366. $this->assertEquals('foo', $insertedNode->getNode()->textContent);
  367. foreach (['foo'] as $index => $value) {
  368. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  369. }
  370. $insertedNode->insertSiblingAfter(new Element('li', 'baz'));
  371. foreach (['foo', 'baz'] as $index => $value) {
  372. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  373. }
  374. $insertedNode->insertSiblingAfter(new Element('li', 'bar'));
  375. foreach (['foo', 'bar', 'baz'] as $index => $value) {
  376. $this->assertEquals($value, $list->getNode()->childNodes->item($index)->textContent);
  377. }
  378. }
  379. public function testHas()
  380. {
  381. $document = new DOMDocument();
  382. $document->loadHTML('<div><span class="foo">bar</span></div>');
  383. $node = $document->getElementsByTagName('div')->item(0);
  384. $element = new Element($node);
  385. $this->assertTrue($element->has('.foo'));
  386. $this->assertFalse($element->has('.bar'));
  387. }
  388. /**
  389. * @dataProvider findTests
  390. */
  391. public function testFind($html, $selector, $type, $count)
  392. {
  393. $document = new DOMDocument();
  394. $document->loadHTML($html);
  395. $domElement = $document->getElementsByTagName('body')->item(0);
  396. $element = new Element($domElement);
  397. $elements = $element->find($selector, $type);
  398. $this->assertTrue(is_array($elements));
  399. $this->assertEquals($count, count($elements));
  400. foreach ($elements as $element) {
  401. $this->assertInstanceOf('DiDom\Element', $element);
  402. }
  403. }
  404. public function testFindInDocumentWithoutOwnerDocument()
  405. {
  406. $this->expectException(LogicException::class);
  407. $element = new Element(new DOMElement('div'));
  408. $element->findInDocument('.foo');
  409. }
  410. public function testFindInDocument()
  411. {
  412. $html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
  413. $document = new Document($html);
  414. $items = $document->find('li');
  415. $list = $document->first('ul');
  416. foreach ($list->find('li') as $index => $item) {
  417. $this->assertFalse($item->is($items[$index]));
  418. }
  419. foreach ($list->findInDocument('li') as $index => $item) {
  420. $this->assertTrue($item->is($items[$index]));
  421. }
  422. $this->assertCount(3, $document->find('li'));
  423. $list->findInDocument('li')[0]->remove();
  424. $this->assertCount(2, $document->find('li'));
  425. }
  426. public function testFirstInDocumentWithoutOwnerDocument()
  427. {
  428. $this->expectException(LogicException::class);
  429. $element = new Element(new DOMElement('div'));
  430. $element->firstInDocument('.foo');
  431. }
  432. public function testFirstInDocument()
  433. {
  434. $html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
  435. $document = new Document($html);
  436. $item = $document->first('li');
  437. $list = $document->first('ul');
  438. $this->assertFalse($item->is($list->first('li')));
  439. $this->assertTrue($item->is($list->firstInDocument('li')));
  440. $this->assertCount(3, $document->find('li'));
  441. $list->findInDocument('li')[0]->remove();
  442. $this->assertCount(2, $document->find('li'));
  443. }
  444. public function testFirst()
  445. {
  446. $html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
  447. $document = new Document($html);
  448. $list = $document->first('ul');
  449. $item = $list->getNode()->childNodes->item(0);
  450. $this->assertEquals($item, $list->first('li')->getNode());
  451. $list = new Element('ul');
  452. $this->assertNull($list->first('li'));
  453. }
  454. /**
  455. * @dataProvider findTests
  456. */
  457. public function testFindAndReturnDomElement($html, $selector, $type, $count)
  458. {
  459. $document = new DOMDocument();
  460. $document->loadHTML($html);
  461. $node = $document->getElementsByTagName('body')->item(0);
  462. $element = new Element($node);
  463. $elements = $element->find($selector, $type, false);
  464. $this->assertTrue(is_array($elements));
  465. $this->assertEquals($count, count($elements));
  466. foreach ($elements as $element) {
  467. $this->assertInstanceOf('DOMElement', $element);
  468. }
  469. }
  470. public function findTests()
  471. {
  472. $html = $this->loadFixture('posts.html');
  473. return array(
  474. array($html, '.post h2', Query::TYPE_CSS, 3),
  475. array($html, '.fake h2', Query::TYPE_CSS, 0),
  476. array($html, '.post h2, .post p', Query::TYPE_CSS, 6),
  477. array($html, "//*[contains(concat(' ', normalize-space(@class), ' '), ' post ')]", Query::TYPE_XPATH, 3),
  478. );
  479. }
  480. public function testXpath()
  481. {
  482. $html = $this->loadFixture('posts.html');
  483. $document = new DOMDocument();
  484. $document->loadHTML($html);
  485. $node = $document->getElementsByTagName('body')->item(0);
  486. $element = new Element($node);
  487. $elements = $element->xpath("//*[contains(concat(' ', normalize-space(@class), ' '), ' post ')]");
  488. $this->assertTrue(is_array($elements));
  489. $this->assertEquals(3, count($elements));
  490. foreach ($elements as $element) {
  491. $this->assertInstanceOf('DiDom\Element', $element);
  492. }
  493. }
  494. public function testCount()
  495. {
  496. $html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
  497. $document = new Document($html, false);
  498. $list = $document->first('ul');
  499. $this->assertEquals(3, $list->count('li'));
  500. $document = new Element('ul');
  501. $this->assertEquals(0, $document->count('li'));
  502. }
  503. public function testMatchesStrictWithoutTagName()
  504. {
  505. $this->expectException(RuntimeException::class);
  506. $element = new Element('ul', null, ['id' => 'foo', 'class' => 'bar baz']);
  507. $element->matches('#foo.bar.baz', true);
  508. }
  509. public function testMatches()
  510. {
  511. $element = new Element('ul', null, ['id' => 'foo', 'class' => 'bar baz']);
  512. $this->assertTrue($element->matches('ul'));
  513. $this->assertTrue($element->matches('#foo'));
  514. $this->assertTrue($element->matches('.bar'));
  515. $this->assertTrue($element->matches('ul#foo.bar.baz'));
  516. $this->assertFalse($element->matches('a#foo.bar.baz'));
  517. // strict
  518. $this->assertTrue($element->matches('ul#foo.bar.baz', true));
  519. $this->assertFalse($element->matches('ul#foo.bar', true));
  520. $this->assertFalse($element->matches('ul#foo', true));
  521. $this->assertFalse($element->matches('ul.bar.baz', true));
  522. $this->assertFalse($element->matches('ul.bar.baz', true));
  523. $element = new Element('p');
  524. $this->assertTrue($element->matches('p', true));
  525. $html = '<!DOCTYPE html>
  526. <html lang="en">
  527. <head>
  528. <meta charset="UTF-8">
  529. <title>Document</title>
  530. </head>
  531. <body>
  532. <a href="#"><img src="foo.jpg" alt="Foo"></a>
  533. </body>
  534. </html>';
  535. $document = new Document($html, false);
  536. $anchor = $document->first('a');
  537. $this->assertTrue($anchor->matches('a:has(img[src$=".jpg"])'));
  538. $this->assertTrue($anchor->matches('a img'));
  539. $this->assertFalse($anchor->matches('a img[alt="Bar"]'));
  540. $this->assertFalse($anchor->matches('img'));
  541. $textNode = new DOMText('Foo');
  542. $element = new Element($textNode);
  543. $this->assertFalse($element->matches('#foo'));
  544. $commentNode = new DOMComment('Foo');
  545. $element = new Element($commentNode);
  546. $this->assertFalse($element->matches('#foo'));
  547. }
  548. public function testHasAttribute()
  549. {
  550. $node = $this->createDomElement('input');
  551. $element = new Element($node);
  552. $this->assertFalse($element->hasAttribute('value'));
  553. $node->setAttribute('value', 'test');
  554. $this->assertTrue($element->hasAttribute('value'));
  555. }
  556. public function testSetAttributeWithInvalidValue()
  557. {
  558. $this->expectException(InvalidArgumentException::class);
  559. $element = new Element('input');
  560. $element->setAttribute('value', []);
  561. }
  562. public function testSetAttribute()
  563. {
  564. $node = $this->createDomElement('input');
  565. $element = new Element($node);
  566. $element->setAttribute('value', 'foo');
  567. $this->assertEquals('foo', $element->getNode()->getAttribute('value'));
  568. $element->setAttribute('value', 10);
  569. $this->assertEquals('10', $element->getNode()->getAttribute('value'));
  570. $element->setAttribute('value', 3.14);
  571. $this->assertEquals('3.14', $element->getNode()->getAttribute('value'));
  572. }
  573. public function testGetAttribute()
  574. {
  575. $node = $this->createDomElement('input');
  576. $element = new Element($node);
  577. $this->assertEquals(null, $element->getAttribute('value'));
  578. $this->assertEquals('default', $element->getAttribute('value', 'default'));
  579. $node->setAttribute('value', 'test');
  580. $this->assertEquals('test', $element->getAttribute('value'));
  581. }
  582. public function testRemoveAttribute()
  583. {
  584. $domElement = $this->createDomElement('input', '', ['name' => 'username']);
  585. $element = new Element($domElement);
  586. $this->assertTrue($element->getNode()->hasAttribute('name'));
  587. $result = $element->removeAttribute('name');
  588. $this->assertEquals(0, $element->getNode()->attributes->length);
  589. $this->assertFalse($element->getNode()->hasAttribute('name'));
  590. $this->assertEquals($result, $element);
  591. }
  592. public function testRemoveAllAttributes()
  593. {
  594. $attributes = ['type' => 'text', 'name' => 'username'];
  595. $domElement = $this->createDomElement('input', '', $attributes);
  596. $element = new Element($domElement);
  597. $result = $element->removeAllAttributes();
  598. $this->assertEquals(0, $element->getNode()->attributes->length);
  599. $this->assertEquals($result, $element);
  600. }
  601. public function testRemoveAllAttributesWithExclusion()
  602. {
  603. $attributes = ['type' => 'text', 'name' => 'username'];
  604. $domElement = $this->createDomElement('input', '', $attributes);
  605. $element = new Element($domElement);
  606. $element->removeAllAttributes(['name']);
  607. $this->assertEquals(1, $element->getNode()->attributes->length);
  608. $this->assertEquals('username', $element->getNode()->getAttribute('name'));
  609. }
  610. public function testAttrSet()
  611. {
  612. $element = new Element('input');
  613. $element->attr('name', 'username');
  614. $this->assertEquals('username', $element->getNode()->getAttribute('name'));
  615. }
  616. public function testAttrGet()
  617. {
  618. $element = new Element('input', null, ['name' => 'username']);
  619. $this->assertEquals('username', $element->attr('name'));
  620. }
  621. public function testAttributes()
  622. {
  623. $attributes = ['type' => 'text', 'name' => 'username', 'value' => 'John'];
  624. $domElement = $this->createDomElement('input', '', $attributes);
  625. $element = new Element($domElement);
  626. $this->assertEquals($attributes, $element->attributes());
  627. $this->assertEquals(['name' => 'username', 'value' => 'John'], $element->attributes(['name', 'value']));
  628. }
  629. public function testAttributesWithText()
  630. {
  631. $element = new Element(new DOMText('Foo'));
  632. $this->assertNull($element->attributes());
  633. }
  634. public function testAttributesWithComment()
  635. {
  636. $element = new Element(new DOMComment('Foo'));
  637. $this->assertNull($element->attributes());
  638. }
  639. public function testStyleWithTextNode()
  640. {
  641. $this->expectException(LogicException::class);
  642. $this->expectExceptionMessage('Style attribute is available only for element nodes');
  643. $element = new Element(new DOMText('foo'));
  644. $element->style();
  645. }
  646. public function testStyleWithCommentNode()
  647. {
  648. $this->expectException(LogicException::class);
  649. $this->expectExceptionMessage('Style attribute is available only for element nodes');
  650. $element = new Element(new DOMComment('foo'));
  651. $element->style();
  652. }
  653. public function testStyle()
  654. {
  655. $element = new Element('div');
  656. $styleAttribute = $element->style();
  657. $this->assertInstanceOf('DiDom\\StyleAttribute', $styleAttribute);
  658. $this->assertSame($element, $styleAttribute->getElement());
  659. $this->assertSame($styleAttribute, $element->style());
  660. $element2 = new Element('div');
  661. $this->assertNotSame($element->style(), $element2->style());
  662. }
  663. public function testHtml()
  664. {
  665. $element = new Element('span', 'hello');
  666. $this->assertEquals('<span>hello</span>', $element->html());
  667. }
  668. public function testOuterHtml()
  669. {
  670. $innerHtml = 'Plain text <span>Lorem ipsum.</span><span>Lorem ipsum.</span>';
  671. $html = "<div id=\"foo\" class=\"bar baz\">$innerHtml</div>";
  672. $document = new Document($html);
  673. $this->assertEquals('<div id="foo" class="bar baz"></div>', $document->first('#foo')->outerHtml());
  674. }
  675. public function testInnerHtml()
  676. {
  677. $innerHtml = ' Plain text <span>Lorem ipsum.</span><span>Lorem ipsum.</span>';
  678. $html = "<div id=\"root\">$innerHtml</div>";
  679. $document = new Document($html);
  680. $this->assertEquals($innerHtml, $document->first('#root')->innerHtml());
  681. $html = '
  682. <!DOCTYPE html>
  683. <html lang="en">
  684. <head>
  685. <meta charset="UTF-8">
  686. <title>Document</title>
  687. </head>
  688. <body>
  689. English language <br>
  690. Русский язык <br>
  691. اللغة العربية <br>
  692. 漢語 <br>
  693. Tiếng Việt <br>
  694. &lt; &gt;
  695. </body>
  696. </html>
  697. ';
  698. $expectedContent = '
  699. English language <br>
  700. Русский язык <br>
  701. اللغة العربية <br>
  702. 漢語 <br>
  703. Tiếng Việt <br>
  704. &lt; &gt;
  705. ';
  706. $document = new Document($html);
  707. $this->assertEquals($expectedContent, $document->first('body')->innerHtml());
  708. }
  709. public function testInnerHtmlOnXmlElement()
  710. {
  711. $innerXml = 'Plain text <span>Lorem <single-tag/> ipsum.</span><span>Lorem ipsum.</span>';
  712. $xml = "<div id=\"root\">$innerXml</div>";
  713. $document = new Document($xml, false, 'UTF-8', Document::TYPE_XML);
  714. $expectedXml = 'Plain text <span>Lorem <single-tag></single-tag> ipsum.</span><span>Lorem ipsum.</span>';
  715. $this->assertEquals($expectedXml, $document->first('#root')->innerHtml());
  716. }
  717. public function testInnerXml()
  718. {
  719. $innerXml = 'Plain text <span>Lorem <single-tag/> ipsum.</span><span>Lorem ipsum.</span>';
  720. $xml = "<div id=\"root\">$innerXml</div>";
  721. $document = new Document($xml, false, 'UTF-8', Document::TYPE_XML);
  722. $this->assertEquals($innerXml, $document->first('#root')->innerXml());
  723. }
  724. public function testSetInnerHtml()
  725. {
  726. $list = new Element('ul');
  727. $html = '<li>One</li><li>Two</li><li>Three</li>';
  728. $this->assertEquals($list, $list->setInnerHtml($html));
  729. $this->assertEquals(['One', 'Two', 'Three'], $list->find('li::text'));
  730. // check inner HTML rewrite works
  731. $html = '<li>Foo</li><li>Bar</li><li>Baz</li>';
  732. $this->assertEquals($list, $list->setInnerHtml($html));
  733. $this->assertEquals(['Foo', 'Bar', 'Baz'], $list->find('li::text'));
  734. $html = '<div id="root"></div>';
  735. $innerHtml = ' Plain text <span>Lorem ipsum.</span><span>Lorem ipsum.</span>';
  736. $document = new Document($html, false);
  737. $document->first('#root')->setInnerHtml($innerHtml);
  738. $this->assertEquals($innerHtml, $document->first('#root')->innerHtml());
  739. }
  740. public function testSetInnerXml()
  741. {
  742. $element = new Element('div');
  743. $element->setInnerXml(' Foo <span>Bar</span><!-- Baz --><![CDATA[
  744. <root>Hello world!</root>
  745. ]]>');
  746. $children = $element->getNode()->childNodes;
  747. $this->assertInstanceOf(DOMText::class, $children[0]);
  748. $this->assertEquals(' Foo ', $children[0]->textContent);
  749. $this->assertInstanceOf(DOMElement::class, $children[1]);
  750. $this->assertEquals('Bar', $children[1]->textContent);
  751. $this->assertInstanceOf(DOMComment::class, $children[2]);
  752. $this->assertEquals(' Baz ', $children[2]->textContent);
  753. $this->assertInstanceOf(DOMCdataSection::class, $children[3]);
  754. $this->assertEquals('<root>Hello world!</root>', trim($children[3]->textContent));
  755. }
  756. public function testXml()
  757. {
  758. $element = new Element('span', 'hello');
  759. $prolog = '<?xml version="1.0" encoding="UTF-8"?>'."\n";
  760. $this->assertEquals($prolog.'<span>hello</span>', $element->xml());
  761. }
  762. public function testXmlWithOptions()
  763. {
  764. $html = '<html><body><span></span></body></html>';
  765. $document = new Document();
  766. $document->loadHtml($html);
  767. $element = $document->find('span')[0];
  768. $prolog = '<?xml version="1.0" encoding="UTF-8"?>'."\n";
  769. $this->assertEquals($prolog.'<span/>', $element->xml());
  770. $this->assertEquals($prolog.'<span></span>', $element->xml(LIBXML_NOEMPTYTAG));
  771. }
  772. public function testGetText()
  773. {
  774. $element = new Element('span', 'hello');
  775. $this->assertEquals('hello', $element->text());
  776. }
  777. public function testSetValue()
  778. {
  779. $element = new Element('span', 'hello');
  780. $element->setValue('test');
  781. $this->assertEquals('test', $element->text());
  782. }
  783. public function testIsElementNode()
  784. {
  785. $element = new Element('div');
  786. $element->setInnerHtml(' Foo <span>Bar</span><!-- Baz -->');
  787. $children = $element->children();
  788. $this->assertFalse($children[0]->isElementNode());
  789. $this->assertTrue($children[1]->isElementNode());
  790. $this->assertFalse($children[2]->isElementNode());
  791. }
  792. public function testIsTextNode()
  793. {
  794. $element = new Element('div');
  795. $element->setInnerHtml(' Foo <span>Bar</span><!-- Baz -->');
  796. $children = $element->children();
  797. $this->assertTrue($children[0]->isTextNode());
  798. $this->assertFalse($children[1]->isTextNode());
  799. $this->assertFalse($children[2]->isTextNode());
  800. }
  801. public function testIsCommentNode()
  802. {
  803. $element = new Element('div');
  804. $element->setInnerHtml(' Foo <span>Bar</span><!-- Baz --><![CDATA[
  805. <root>Hello world!</root>
  806. ]]>');
  807. $children = $element->children();
  808. $this->assertFalse($children[0]->isCommentNode());
  809. $this->assertFalse($children[1]->isCommentNode());
  810. $this->assertTrue($children[2]->isCommentNode());
  811. $this->assertFalse($children[3]->isCommentNode());
  812. }
  813. public function testIsCdataSectionNode()
  814. {
  815. $element = new Element('div');
  816. $element->setInnerXml(' Foo <span>Bar</span><!-- Baz --><![CDATA[
  817. <root>Hello world!</root>
  818. ]]>');
  819. $children = $element->children();
  820. $this->assertFalse($children[0]->isCdataSectionNode());
  821. $this->assertFalse($children[1]->isCdataSectionNode());
  822. $this->assertFalse($children[2]->isCdataSectionNode());
  823. $this->assertTrue($children[3]->isCdataSectionNode());
  824. }
  825. public function testIs()
  826. {
  827. $element = new Element('span', 'hello');
  828. $element2 = new Element('span', 'hello');
  829. $this->assertTrue($element->is($element));
  830. $this->assertFalse($element->is($element2));
  831. }
  832. public function testIsWithInvalidArgument()
  833. {
  834. $this->expectException(InvalidArgumentException::class);
  835. $element = new Element('span', 'hello');
  836. $element->is(null);
  837. }
  838. public function testParent()
  839. {
  840. $html = $this->loadFixture('posts.html');
  841. $document = new Document($html, false);
  842. $element = $document->createElement('span', 'value');
  843. $this->assertEquals($document->getDocument(), $element->ownerDocument()->getDocument());
  844. }
  845. public function testClosest()
  846. {
  847. // without body and html tags
  848. $html = '
  849. <nav>
  850. <ul class="menu">
  851. <li><a href="#">Foo</a></li>
  852. <li><a href="#">Bar</a></li>
  853. <li><a href="#">Baz</a></li>
  854. </ul>
  855. </nav>
  856. ';
  857. $document = new Document($html);
  858. $menu = $document->first('.menu');
  859. $link = $document->first('a');
  860. $this->assertNull($link->closest('.unknown-class'));
  861. $this->assertEquals($menu, $link->closest('.menu'));
  862. $html = '<!DOCTYPE html>
  863. <html>
  864. <body>
  865. <nav></nav>
  866. <ul class="menu">
  867. <li><a href="#">Foo</a></li>
  868. <li><a href="#">Bar</a></li>
  869. <li><a href="#">Baz</a></li>
  870. </ul>
  871. </body>
  872. </html>';
  873. $document = new Document($html);
  874. $this->assertNull($document->first('ul.menu')->closest('nav'));
  875. }
  876. // =========================
  877. // previousSibling
  878. // =========================
  879. public function testPreviousSibling()
  880. {
  881. $html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
  882. $document = new Document($html, false);
  883. $list = $document->first('ul')->getNode();
  884. $item = $list->childNodes->item(0);
  885. $item = new Element($item);
  886. $this->assertNull($item->previousSibling());
  887. $item = $list->childNodes->item(1);
  888. $item = new Element($item);
  889. $expectedNode = $list->childNodes->item(0);
  890. $this->assertEquals($expectedNode, $item->previousSibling()->getNode());
  891. }
  892. public function testPreviousSiblingWithTextNode()
  893. {
  894. $html = '<p>Foo <span>Bar</span> Baz</p>';
  895. $document = new Document($html, false);
  896. $span = $document->first('span');
  897. $expectedNode = $span->getNode()->previousSibling;
  898. $this->assertEquals($expectedNode, $span->previousSibling()->getNode());
  899. }
  900. public function testPreviousSiblingWithCommentNode()
  901. {
  902. $html = '<p><!-- Foo --><span>Bar</span> Baz</p>';
  903. $document = new Document($html, false);
  904. $span = $document->first('span');
  905. $expectedNode = $span->getNode()->previousSibling;
  906. $this->assertEquals($expectedNode, $span->previousSibling()->getNode());
  907. }
  908. public function testPreviousSiblingWithSelector()
  909. {
  910. $html =
  911. '<ul>'.
  912. '<li><a href="https://amazon.com">Amazon</a></li>'.
  913. '<li><a href="https://facebook.com">Facebook</a></li>'.
  914. '<li><a href="https://google.com">Google</a></li>'.
  915. '<li><a href="https://www.w3.org">W3C</a></li>'.
  916. '<li><a href="https://wikipedia.org">Wikipedia</a></li>'.
  917. '</ul>'
  918. ;
  919. $document = new Document($html, false);
  920. $list = $document->first('ul');
  921. $item = $list->getNode()->childNodes->item(4);
  922. $item = new Element($item);
  923. $expectedNode = $list->getNode()->childNodes->item(2);
  924. $this->assertEquals($expectedNode, $item->previousSibling('li:has(a[href*="google"])')->getNode());
  925. }
  926. public function testPreviousSiblingWithSelectorElementMissed()
  927. {
  928. $html =
  929. '<ul>'.
  930. '<li><a href="https://amazon.com">Amazon</a></li>'.
  931. '<li><a href="https://facebook.com">Facebook</a></li>'.
  932. '<li><a href="https://google.com">Google</a></li>'.
  933. '<li><a href="https://www.w3.org">W3C</a></li>'.
  934. '<li><a href="https://wikipedia.org">Wikipedia</a></li>'.
  935. '</ul>'
  936. ;
  937. $document = new Document($html, false);
  938. $list = $document->first('ul');
  939. $item = $list->getNode()->childNodes->item(4);
  940. $item = new Element($item);
  941. $this->assertNull($item->previousSibling('li:has(a[href*="acme"])'));
  942. }
  943. public function testPreviousSiblingWithNodeType()
  944. {
  945. $html = '<p>Foo <span>Bar</span><!--qwe--> Baz <span>Qux</span></p>';
  946. $document = new Document($html, false);
  947. $paragraph = $document->first('p');
  948. $span = $document->find('span')[1];
  949. $expectedNode = $paragraph->getNode()->childNodes->item(1);
  950. $this->assertEquals($expectedNode, $span->previousSibling(null, 'DOMElement')->getNode());
  951. $expectedNode = $paragraph->getNode()->childNodes->item(2);
  952. $this->assertEquals($expectedNode, $span->previousSibling(null, 'DOMComment')->getNode());
  953. }
  954. public function testPreviousSiblingWithInvalidNodeType()
  955. {
  956. $this->expectException(RuntimeException::class);
  957. $html = '<p>Foo <span>Bar</span><!--qwe--> Baz <span>Qux</span></p>';
  958. $document = new Document($html, false);
  959. $span = $document->find('span')[1];
  960. $span->previousSibling(null, 'foo');
  961. }
  962. /**
  963. * @dataProvider previousSiblingWithSelectorAndNotDomElementNodeTypeDataProvider
  964. *
  965. * @param string $nodeType
  966. */
  967. public function testPreviousSiblingWithSelectorAndNotDomElement($nodeType)
  968. {
  969. $this->expectException(LogicException::class);
  970. $html =
  971. '<ul>'.
  972. '<li><a href="https://amazon.com">Amazon</a></li>'.
  973. '<li><a href="https://facebook.com">Facebook</a></li>'.
  974. '<li><a href="https://google.com">Google</a></li>'.
  975. '<li><a href="https://www.w3.org">W3C</a></li>'.
  976. '<li><a href="https://wikipedia.org">Wikipedia</a></li>'.
  977. '</ul>'
  978. ;
  979. $document = new Document($html, false);
  980. $list = $document->first('ul');
  981. $item = $list->getNode()->childNodes->item(4);
  982. $item = new Element($item);
  983. $item->previousSibling('li:has(a[href$=".com"])', $nodeType);
  984. }
  985. public function previousSiblingWithSelectorAndNotDomElementNodeTypeDataProvider()
  986. {
  987. return [['DOMText'], ['DOMComment']];
  988. }
  989. // =========================
  990. // previousSiblings
  991. // =========================
  992. public function testPreviousSiblings()
  993. {
  994. $html = '<p>Foo <span>Bar</span> Baz <span>Qux</span></p>';
  995. $document = new Document($html, false);
  996. $paragraph = $document->first('p');
  997. $span = $paragraph->find('span')[1];
  998. $childNodes = $paragraph->getNode()->childNodes;
  999. $expectedResult = [
  1000. $childNodes->item(0),
  1001. $childNodes->item(1),
  1002. $childNodes->item(2),
  1003. ];
  1004. $previousSiblings = $span->previousSiblings();
  1005. $this->assertCount(count($expectedResult), $previousSiblings);
  1006. foreach ($previousSiblings as $index => $previousSibling) {
  1007. $this->assertEquals($expectedResult[$index], $previousSibling->getNode());
  1008. }
  1009. }
  1010. public function testPreviousSiblingsWithSelector()
  1011. {
  1012. $html =
  1013. '<ul>'.
  1014. '<li><a href="https://amazon.com">Amazon</a></li>'.
  1015. '<li><a href="https://facebook.com">Facebook</a></li>'.
  1016. '<li><a href="https://google.com">Google</a></li>'.
  1017. '<li><a href="https://www.w3.org">W3C</a></li>'.
  1018. '<li><a href="https://wikipedia.org">Wikipedia</a></li>'.
  1019. '</ul>'
  1020. ;
  1021. $document = new Document($html, false);
  1022. $list = $document->first('ul');
  1023. $item = $list->getNode()->childNodes->item(4);
  1024. $item = new Element($item);
  1025. $childNodes = $list->getNode()->childNodes;
  1026. $expectedResult = [
  1027. $childNodes->item(0),
  1028. $childNodes->item(1),
  1029. $childNodes->item(2),
  1030. ];
  1031. $previousSiblings = $item->previousSiblings('li:has(a[href$=".com"])');
  1032. $this->assertCount(count($expectedResult), $previousSiblings);
  1033. foreach ($previousSiblings as $index => $previousSibling) {
  1034. $this->assertEquals($expectedResult[$index], $previousSibling->getNode());
  1035. }
  1036. }
  1037. public function testPreviousSiblingsWithNodeType()
  1038. {
  1039. $html = '<p>Foo <span>Bar</span><!--qwe--> Baz <span>Qux</span></p>';
  1040. $document = new Document($html, false);
  1041. $paragraph = $document->first('p');
  1042. $span = $document->find('span')[1];
  1043. $childNodes = $paragraph->getNode()->childNodes;
  1044. $expectedResult = [
  1045. $childNodes->item(1),
  1046. ];
  1047. $previousSiblings = $span->previousSiblings(null, 'DOMElement');
  1048. $this->assertCount(count($expectedResult), $previousSiblings);
  1049. foreach ($previousSiblings as $index => $previousSibling) {
  1050. $this->assertEquals($expectedResult[$index], $previousSibling->getNode());
  1051. }
  1052. $expectedResult = [
  1053. $childNodes->item(2),
  1054. ];
  1055. $previousSiblings = $span->previousSiblings(null, 'DOMComment');
  1056. $this->assertCount(count($expectedResult), $previousSiblings);
  1057. foreach ($previousSiblings as $index => $previousSibling) {
  1058. $this->assertEquals($expectedResult[$index], $previousSibling->getNode());
  1059. }
  1060. }
  1061. public function testPreviousSiblingsWithInvalidNodeType()
  1062. {
  1063. $this->expectException(RuntimeException::class);
  1064. $html = '<p>Foo <span>Bar</span><!--qwe--> Baz <span>Qux</span></p>';
  1065. $document = new Document($html, false);
  1066. $span = $document->find('span')[1];
  1067. $span->previousSibling(null, 'foo');
  1068. }
  1069. /**
  1070. * @dataProvider previousSiblingsWithSelectorAndNotDomElementNodeTypeDataProvider
  1071. *
  1072. * @param string $nodeType
  1073. */
  1074. public function testPreviousSiblingsWithSelectorAndNotDomElement($nodeType)
  1075. {
  1076. $this->expectException(LogicException::class);
  1077. $html =
  1078. '<ul>'.
  1079. '<li><a href="https://amazon.com">Amazon</a></li>'.
  1080. '<li><a href="https://facebook.com">Facebook</a></li>'.
  1081. '<li><a href="https://google.com">Google</a></li>'.
  1082. '<li><a href="https://www.w3.org">W3C</a></li>'.
  1083. '<li><a href="https://wikipedia.org">Wikipedia</a></li>'.
  1084. '</ul>'
  1085. ;
  1086. $document = new Document($html, false);
  1087. $list = $document->first('ul');
  1088. $item = $list->getNode()->childNodes->item(4);
  1089. $item = new Element($item);
  1090. $item->previousSiblings('li:has(a[href$=".com"])', $nodeType);
  1091. }
  1092. public function previousSiblingsWithSelectorAndNotDomElementNodeTypeDataProvider()
  1093. {
  1094. return [['DOMText'], ['DOMComment']];
  1095. }
  1096. // =========================
  1097. // nextSibling
  1098. // =========================
  1099. public function testNextSibling()
  1100. {
  1101. $html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
  1102. $document = new Document($html, false);
  1103. $list = $document->first('ul');
  1104. $item = $list->getNode()->childNodes->item(2);
  1105. $item = new Element($item);
  1106. $this->assertNull($item->nextSibling());
  1107. $item = $list->getNode()->childNodes->item(0);
  1108. $item = new Element($item);
  1109. $expectedNode = $list->getNode()->childNodes->item(1);
  1110. $this->assertEquals($expectedNode, $item->nextSibling()->getNode());
  1111. }
  1112. public function testNextSiblingWithTextNode()
  1113. {
  1114. $html = '<p>Foo <span>Bar</span> Baz</p>';
  1115. $document = new Document($html, false);
  1116. $paragraph = $document->first('p');
  1117. $span = $paragraph->first('span');
  1118. $expectedNode = $span->getNode()->nextSibling;
  1119. $this->assertEquals($expectedNode, $span->nextSibling()->getNode());
  1120. }
  1121. public function testNextSiblingWithCommentNode()
  1122. {
  1123. $html = '<p>Foo <span>Bar</span><!-- Baz --></p>';
  1124. $document = new Document($html, false);
  1125. $paragraph = $document->first('p');
  1126. $span = $paragraph->first('span');
  1127. $expectedNode = $span->getNode()->nextSibling;
  1128. $this->assertEquals($expectedNode, $span->nextSibling()->getNode());
  1129. }
  1130. public function testNextSiblingWithSelector()
  1131. {
  1132. $html =
  1133. '<ul>'.
  1134. '<li><a href="https://amazon.com">Amazon</a></li>'.
  1135. '<li><a href="https://facebook.com">Facebook</a></li>'.
  1136. '<li><a href="https://google.com">Google</a></li>'.
  1137. '<li><a href="https://www.w3.org">W3C</a></li>'.
  1138. '<li><a href="https://wikipedia.org">Wikipedia</a></li>'.
  1139. '</ul>'
  1140. ;
  1141. $document = new Document($html, false);
  1142. $list = $document->first('ul');
  1143. $item = $list->getNode()->childNodes->item(0);
  1144. $item = new Element($item);
  1145. $expectedNode = $list->getNode()->childNodes->item(3);
  1146. $this->assertEquals($expectedNode, $item->nextSibling('li:has(a[href*="w3"])')->getNode());
  1147. }
  1148. public function testNextSiblingWithSelectorElementMissed()
  1149. {
  1150. $html =
  1151. '<ul>'.
  1152. '<li><a href="https://amazon.com">Amazon</a></li>'.
  1153. '<li><a href="https://facebook.com">Facebook</a></li>'.
  1154. '<li><a href="https://google.com">Google</a></li>'.
  1155. '<li><a href="https://www.w3.org">W3C</a></li>'.
  1156. '<li><a href="https://wikipedia.org">Wikipedia</a></li>'.
  1157. '</ul>'
  1158. ;
  1159. $document = new Document($html, false);
  1160. $list = $document->first('ul');
  1161. $item = $list->getNode()->childNodes->item(0);
  1162. $item = new Element($item);
  1163. $this->assertNull($item->nextSibling('li:has(a[href*="acme"])'));
  1164. }
  1165. public function testNextSiblingWithNodeType()
  1166. {
  1167. $html = '<p>Foo <span>Bar</span> Baz <!--qwe--><span>Qux</span></p>';
  1168. $document = new Document($html, false);
  1169. $paragraph = $document->first('p');
  1170. $span = $document->find('span')[0];
  1171. $expectedNode = $paragraph->getNode()->childNodes->item(4);
  1172. $this->assertEquals($expectedNode, $span->nextSibling(null, 'DOMElement')->getNode());
  1173. $expectedNode = $paragraph->getNode()->childNodes->item(3);
  1174. $this->assertEquals($expectedNode, $span->nextSibling(null, 'DOMComment')->getNode());
  1175. }
  1176. public function testNextSiblingWithInvalidNodeType()
  1177. {
  1178. $this->expectException(RuntimeException::class);
  1179. $html = '<p>Foo <span>Bar</span> Baz <!--qwe--><span>Qux</span></p>';
  1180. $document = new Document($html, false);
  1181. $span = $document->find('span')[0];
  1182. $span->nextSibling(null, 'foo');
  1183. }
  1184. /**
  1185. * @dataProvider nextSiblingWithSelectorAndNotDomElementNodeTypeDataProvider
  1186. *
  1187. * @param string $nodeType
  1188. */
  1189. public function testNextSiblingWithSelectorAndNotDomElement($nodeType)
  1190. {
  1191. $this->expectException(LogicException::class);
  1192. $html =
  1193. '<ul>'.
  1194. '<li><a href="https://amazon.com">Amazon</a></li>'.
  1195. '<li><a href="https://facebook.com">Facebook</a></li>'.
  1196. '<li><a href="https://google.com">Google</a></li>'.
  1197. '<li><a href="https://www.w3.org">W3C</a></li>'.
  1198. '<li><a href="https://wikipedia.org">Wikipedia</a></li>'.
  1199. '</ul>'
  1200. ;
  1201. $document = new Document($html, false);
  1202. $list = $document->first('ul');
  1203. $item = $list->getNode()->childNodes->item(0);
  1204. $item = new Element($item);
  1205. $item->nextSibling('li:has(a[href$=".com"])', $nodeType);
  1206. }
  1207. public function nextSiblingWithSelectorAndNotDomElementNodeTypeDataProvider()
  1208. {
  1209. return [['DOMText'], ['DOMComment']];
  1210. }
  1211. // =========================
  1212. // nextSiblings
  1213. // =========================
  1214. public function testNextSiblings()
  1215. {
  1216. $html = '<p>Foo <span>Bar</span> Baz <span>Qux</span></p>';
  1217. $document = new Document($html, false);
  1218. $paragraph = $document->first('p');
  1219. $span = $paragraph->find('span')[0];
  1220. $childNodes = $paragraph->getNode()->childNodes;
  1221. $expectedResult = [
  1222. $childNodes->item(2),
  1223. $childNodes->item(3),
  1224. ];
  1225. $nextSiblings = $span->nextSiblings();
  1226. $this->assertCount(count($expectedResult), $nextSiblings);
  1227. foreach ($nextSiblings as $index => $nextSibling) {
  1228. $this->assertEquals($expectedResult[$index], $nextSibling->getNode());
  1229. }
  1230. }
  1231. public function testNextSiblingsWithSelector()
  1232. {
  1233. $html =
  1234. '<ul>'.
  1235. '<li><a href="https://amazon.com">Amazon</a></li>'.
  1236. '<li><a href="https://facebook.com">Facebook</a></li>'.
  1237. '<li><a href="https://google.com">Google</a></li>'.
  1238. '<li><a href="https://www.w3.org">W3C</a></li>'.
  1239. '<li><a href="https://wikipedia.org">Wikipedia</a></li>'.
  1240. '</ul>'
  1241. ;
  1242. $document = new Document($html, false);
  1243. $list = $document->first('ul');
  1244. $item = $list->getNode()->childNodes->item(0);
  1245. $item = new Element($item);
  1246. $childNodes = $list->getNode()->childNodes;
  1247. $expectedResult = [
  1248. $childNodes->item(1),
  1249. $childNodes->item(2),
  1250. ];
  1251. $nextSiblings = $item->nextSiblings('li:has(a[href$=".com"])');
  1252. $this->assertCount(count($expectedResult), $nextSiblings);
  1253. foreach ($nextSiblings as $index => $nextSibling) {
  1254. $this->assertEquals($expectedResult[$index], $nextSibling->getNode());
  1255. }
  1256. }
  1257. public function testNextSiblingsWithNodeType()
  1258. {
  1259. $html = '<p>Foo <span>Bar</span><!--qwe--> Baz <span>Qux</span></p>';
  1260. $document = new Document($html, false);
  1261. $paragraph = $document->first('p');
  1262. $span = $document->find('span')[0];
  1263. $childNodes = $paragraph->getNode()->childNodes;
  1264. $expectedResult = [
  1265. $childNodes->item(4),
  1266. ];
  1267. $previousSiblings = $span->nextSiblings(null, 'DOMElement');
  1268. $this->assertCount(count($expectedResult), $previousSiblings);
  1269. foreach ($previousSiblings as $index => $previousSibling) {
  1270. $this->assertEquals($expectedResult[$index], $previousSibling->getNode());
  1271. }
  1272. $expectedResult = [
  1273. $childNodes->item(2),
  1274. ];
  1275. $previousSiblings = $span->nextSiblings(null, 'DOMComment');
  1276. $this->assertCount(count($expectedResult), $previousSiblings);
  1277. foreach ($previousSiblings as $index => $previousSibling) {
  1278. $this->assertEquals($expectedResult[$index], $previousSibling->getNode());
  1279. }
  1280. }
  1281. public function testNextSiblingsWithInvalidNodeType()
  1282. {
  1283. $this->expectException(RuntimeException::class);
  1284. $html = '<p>Foo <span>Bar</span><!--qwe--> Baz <span>Qux</span></p>';
  1285. $document = new Document($html, false);
  1286. $span = $document->find('span')[0];
  1287. $span->nextSiblings(null, 'foo');
  1288. }
  1289. /**
  1290. * @dataProvider nextSiblingsWithSelectorAndNotDomElementNodeTypeDataProvider
  1291. *
  1292. * @param string $nodeType
  1293. */
  1294. public function testNextSiblingsWithSelectorAndNotDomElement($nodeType)
  1295. {
  1296. $this->expectException(LogicException::class);
  1297. $html =
  1298. '<ul>'.
  1299. '<li><a href="https://amazon.com">Amazon</a></li>'.
  1300. '<li><a href="https://facebook.com">Facebook</a></li>'.
  1301. '<li><a href="https://google.com">Google</a></li>'.
  1302. '<li><a href="https://www.w3.org">W3C</a></li>'.
  1303. '<li><a href="https://wikipedia.org">Wikipedia</a></li>'.
  1304. '</ul>'
  1305. ;
  1306. $document = new Document($html, false);
  1307. $list = $document->first('ul');
  1308. $item = $list->getNode()->childNodes->item(0);
  1309. $item = new Element($item);
  1310. $item->nextSiblings('li:has(a[href$=".com"])', $nodeType);
  1311. }
  1312. public function nextSiblingsWithSelectorAndNotDomElementNodeTypeDataProvider()
  1313. {
  1314. return [['DOMText'], ['DOMComment']];
  1315. }
  1316. public function testChild()
  1317. {
  1318. $html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
  1319. $document = new Document($html, false);
  1320. $list = $document->first('ul');
  1321. $this->assertEquals($list->getNode()->childNodes->item(0), $list->child(0)->getNode());
  1322. $this->assertEquals($list->getNode()->childNodes->item(2), $list->child(2)->getNode());
  1323. $this->assertNull($list->child(3));
  1324. // with text nodes
  1325. $html = '<p>Foo <span>Bar</span> Baz</p>';
  1326. $document = new Document($html, false);
  1327. $paragraph = $document->first('p');
  1328. $child = $paragraph->getNode()->childNodes->item(0);
  1329. $this->assertEquals($child, $paragraph->child(0)->getNode());
  1330. }
  1331. public function testFirstChild()
  1332. {
  1333. $html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
  1334. $document = new Document($html, false);
  1335. $list = $document->first('ul');
  1336. $this->assertEquals($list->getNode()->firstChild, $list->firstChild()->getNode());
  1337. $list = new Element('ul');
  1338. $this->assertNull($list->firstChild());
  1339. // with text nodes
  1340. $html = '<p>Foo <span>Bar</span> Baz</p>';
  1341. $document = new Document($html, false);
  1342. $paragraph = $document->first('p');
  1343. $firstChild = $paragraph->getNode()->firstChild;
  1344. $this->assertEquals($firstChild, $paragraph->firstChild()->getNode());
  1345. }
  1346. public function testLastChild()
  1347. {
  1348. $html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
  1349. $document = new Document($html, false);
  1350. $list = $document->first('ul');
  1351. $this->assertEquals($list->getNode()->lastChild, $list->lastChild()->getNode());
  1352. $list = new Element('ul');
  1353. $this->assertNull($list->lastChild());
  1354. // with text nodes
  1355. $html = '<p>Foo <span>Bar</span> Baz</p>';
  1356. $document = new Document($html, false);
  1357. $paragraph = $document->first('p');
  1358. $lastChild = $paragraph->getNode()->lastChild;
  1359. $this->assertEquals($lastChild, $paragraph->lastChild()->getNode());
  1360. }
  1361. public function testHasChildren()
  1362. {
  1363. $html = '
  1364. <p class="element"><br></p>
  1365. <p class="text">Foo</p>
  1366. <p class="comment"><!-- Foo --></p>
  1367. <p class="empty"></p>
  1368. ';
  1369. $document = new Document($html);
  1370. $this->assertTrue($document->first('.element')->hasChildren());
  1371. $this->assertTrue($document->first('.text')->hasChildren());
  1372. $this->assertTrue($document->first('.comment')->hasChildren());
  1373. $this->assertFalse($document->first('.empty')->hasChildren());
  1374. }
  1375. public function testChildren()
  1376. {
  1377. $html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
  1378. $document = new Document($html, false);
  1379. $list = $document->first('ul');
  1380. $children = $list->children();
  1381. foreach ($list->getNode()->childNodes as $index => $node) {
  1382. $this->assertEquals($node, $children[$index]->getNode());
  1383. }
  1384. // with text nodes
  1385. $html = '<p>Foo <span>Bar</span> Baz</p>';
  1386. $document = new Document($html, false);
  1387. $paragraph = $document->first('p');
  1388. $children = $paragraph->children();
  1389. foreach ($paragraph->getNode()->childNodes as $index => $node) {
  1390. $this->assertEquals($node, $children[$index]->getNode());
  1391. }
  1392. }
  1393. public function testParentWithoutOwner()
  1394. {
  1395. $element = new Element(new DOMElement('span', 'hello'));
  1396. $this->assertNull($element->parent());
  1397. }
  1398. public function testRemoveChild()
  1399. {
  1400. $html = '<div><span>Foo</span></div>';
  1401. $document = new Document($html, false);
  1402. $div = $document->first('div');
  1403. $span = $document->first('span');
  1404. $this->assertEquals($span->getNode(), $div->removeChild($span)->getNode());
  1405. $this->assertCount(0, $document->find('span'));
  1406. }
  1407. public function testRemoveChildren()
  1408. {
  1409. $html = '<div><span>Foo</span>Bar<!-- Baz --></div>';
  1410. $document = new Document($html, false);
  1411. $div = $document->first('div');
  1412. $span = $document->first('span');
  1413. $childNodes = $div->children();
  1414. $removedNodes = $div->removeChildren();
  1415. foreach ($childNodes as $index => $childNode) {
  1416. $this->assertEquals($childNode->getNode(), $removedNodes[$index]->getNode());
  1417. }
  1418. $this->assertCount(0, $document->find('span'));
  1419. }
  1420. public function testRemove()
  1421. {
  1422. $html = '<div><span>Foo</span></div>';
  1423. $document = new Document($html, false);
  1424. $span = $document->first('span');
  1425. $this->assertEquals($span->getNode(), $span->remove()->getNode());
  1426. $this->assertCount(0, $document->find('span'));
  1427. }
  1428. public function testRemoveWithoutParentNode()
  1429. {
  1430. $this->expectException(LogicException::class);
  1431. $element = new Element('div', 'Foo');
  1432. $element->remove();
  1433. }
  1434. public function testReplace()
  1435. {
  1436. $html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
  1437. $document = new Document($html, false);
  1438. $first = $document->find('li')[0];
  1439. $third = $document->find('li')[2];
  1440. $this->assertEquals($first->getNode(), $first->replace($third)->getNode());
  1441. $this->assertEquals($third->getNode(), $document->find('li')[0]->getNode());
  1442. $this->assertCount(3, $document->find('li'));
  1443. // replace without cloning
  1444. $document = new Document($html, false);
  1445. $first = $document->find('li')[0];
  1446. $third = $document->find('li')[2];
  1447. $this->assertEquals($first->getNode(), $first->replace($third, false)->getNode());
  1448. $this->assertEquals($third->getNode(), $document->find('li')[0]->getNode());
  1449. $this->assertCount(2, $document->find('li'));
  1450. }
  1451. public function testReplaceWithNewElement()
  1452. {
  1453. $html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
  1454. $document = new Document($html, false);
  1455. $first = $document->find('li')[0];
  1456. $newElement = new Element('li', 'Foo');
  1457. $this->assertEquals($first->getNode(), $first->replace($newElement)->getNode());
  1458. $this->assertEquals('Foo', $document->find('li')[0]->text());
  1459. $this->assertCount(3, $document->find('li'));
  1460. // replace with new node
  1461. $html = '<span>Foo <a href="#">Bar</a> Baz</span>';
  1462. $document = new Document($html, false);
  1463. $anchor = $document->first('a');
  1464. $textNode = new DOMText($anchor->text());
  1465. $anchor->replace($textNode);
  1466. }
  1467. public function testReplaceWithElementFromAnotherDocument()
  1468. {
  1469. $html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
  1470. $document = new Document($html, false);
  1471. $document2 = new Document($html, false);
  1472. $first = $document->find('li')[0];
  1473. $third = $document2->find('li')[2];
  1474. $this->assertEquals($first->getNode(), $first->replace($third)->getNode());
  1475. $this->assertEquals('Three', $document->find('li')[0]->text());
  1476. $this->assertCount(3, $document->find('li'));
  1477. }
  1478. public function testReplaceWithDocumentFragment()
  1479. {
  1480. $xml = '
  1481. <list>
  1482. <item>Foo</item>
  1483. <item>Bar</item>
  1484. <item>Baz</item>
  1485. </list>
  1486. ';
  1487. $document = new Document();
  1488. $document->loadXml($xml);
  1489. $fragmentXml = '
  1490. <item>Qux</item>
  1491. <item>Quux</item>
  1492. <item>Quuz</item>
  1493. ';
  1494. $documentFragment = $document->createDocumentFragment();
  1495. $documentFragment->appendXml($fragmentXml);
  1496. $document->first('item:nth-child(2)')->replace($documentFragment);
  1497. $expectedContent = ['Foo', 'Qux', 'Quux', 'Quuz', 'Baz'];
  1498. foreach ($document->find('item') as $index => $childNode) {
  1499. $this->assertEquals('item', $childNode->getNode()->tagName);
  1500. $this->assertEquals($expectedContent[$index], $childNode->text());
  1501. }
  1502. }
  1503. public function testReplaceWithInvalidArgument()
  1504. {
  1505. $this->expectException(InvalidArgumentException::class);
  1506. $html = '<ul><li>One</li><li>Two</li><li>Three</li></ul>';
  1507. $document = new Document($html, false);
  1508. $document->find('li')[0]->replace(null);
  1509. }
  1510. public function testReplaceElementWithoutParentNode()
  1511. {
  1512. $this->expectException(LogicException::class);
  1513. $element = new Element('div', 'Foo');
  1514. $element->replace(new Element('div', 'Bar'));
  1515. }
  1516. public function testGetLineNo()
  1517. {
  1518. $element = new Element('div');
  1519. $this->assertEquals(0, $element->getLineNo());
  1520. $html = '<ul>
  1521. <li>One</li>
  1522. <li>Two</li>
  1523. <li>Three</li>
  1524. </ul>';
  1525. $document = new Document($html, false);
  1526. $this->assertEquals(4, $document->find('li')[2]->getLineNo());
  1527. }
  1528. public function testCloneNode()
  1529. {
  1530. $element = new Element('input');
  1531. $cloned = $element->cloneNode(true);
  1532. $this->assertFalse($element->is($cloned));
  1533. }
  1534. public function testGetNode()
  1535. {
  1536. $node = $this->createDomElement('input');
  1537. $element = new Element($node);
  1538. $this->assertEquals($node, $element->getNode());
  1539. }
  1540. public function testGetDocument()
  1541. {
  1542. $html = $this->loadFixture('posts.html');
  1543. $document = new Document($html, false);
  1544. $element = $document->createElement('span', 'value');
  1545. $this->assertEquals($document->getDocument(), $element->ownerDocument()->getDocument());
  1546. }
  1547. public function testToDocument()
  1548. {
  1549. $element = new Element('input');
  1550. $document = $element->toDocument();
  1551. $this->assertInstanceOf('DiDom\Document', $document);
  1552. $this->assertEquals('UTF-8', $document->getDocument()->encoding);
  1553. $document = $element->toDocument('CP1251');
  1554. $this->assertEquals('CP1251', $document->getDocument()->encoding);
  1555. }
  1556. public function testSetMagicMethod()
  1557. {
  1558. $node = $this->createDomElement('input');
  1559. $element = new Element($node);
  1560. $element->name = 'username';
  1561. $this->assertEquals('username', $element->getNode()->getAttribute('name'));
  1562. }
  1563. public function testGetMagicMethod()
  1564. {
  1565. $element = new Element('input', null, ['name' => 'username']);
  1566. $this->assertEquals('username', $element->name);
  1567. }
  1568. public function testIssetMagicMethod()
  1569. {
  1570. $node = $this->createDomElement('input');
  1571. $element = new Element($node);
  1572. $this->assertFalse(isset($element->value));
  1573. $node->setAttribute('value', 'test');
  1574. $element = new Element($node);
  1575. $this->assertTrue(isset($element->value));
  1576. }
  1577. public function testUnsetMagicMethod()
  1578. {
  1579. $element = new Element('input', null, ['name' => 'username']);
  1580. $this->assertTrue($element->hasAttribute('name'));
  1581. unset($element->name);
  1582. $this->assertFalse($element->hasAttribute('name'));
  1583. }
  1584. public function testToString()
  1585. {
  1586. $element = new Element('span', 'hello');
  1587. $this->assertEquals($element->html(), $element->__toString());
  1588. }
  1589. }