OutputRulesTest.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. <?php
  2. namespace Masterminds\HTML5\Tests\Serializer;
  3. use Masterminds\HTML5\Serializer\OutputRules;
  4. use Masterminds\HTML5\Serializer\Traverser;
  5. use Masterminds\HTML5;
  6. class OutputRulesTest extends \Masterminds\HTML5\Tests\TestCase
  7. {
  8. protected $markup = '<!doctype html>
  9. <html lang="en">
  10. <head>
  11. <meta charset="utf-8">
  12. <title>Test</title>
  13. </head>
  14. <body>
  15. <p>This is a test.</p>
  16. </body>
  17. </html>';
  18. /**
  19. * @var HTML5
  20. */
  21. protected $html5;
  22. public function setUp()
  23. {
  24. $this->html5 = $this->getInstance();
  25. }
  26. /**
  27. * Using reflection we make a protected method accessible for testing.
  28. *
  29. * @param string $name
  30. * The name of the method on the Traverser class to test
  31. *
  32. * @return \ReflectionMethod for the specified method
  33. */
  34. public function getProtectedMethod($name)
  35. {
  36. $class = new \ReflectionClass('\Masterminds\HTML5\Serializer\OutputRules');
  37. $method = $class->getMethod($name);
  38. $method->setAccessible(true);
  39. return $method;
  40. }
  41. public function getTraverserProtectedProperty($name)
  42. {
  43. $class = new \ReflectionClass('\Masterminds\HTML5\Serializer\Traverser');
  44. $property = $class->getProperty($name);
  45. $property->setAccessible(true);
  46. return $property;
  47. }
  48. public function getOutputRules($options = array())
  49. {
  50. $options = $options + $this->html5->getOptions();
  51. $stream = fopen('php://temp', 'w');
  52. $dom = $this->html5->loadHTML($this->markup);
  53. $r = new OutputRules($stream, $options);
  54. $t = new Traverser($dom, $stream, $r, $options);
  55. return array(
  56. $r,
  57. $stream,
  58. );
  59. }
  60. public function testDocument()
  61. {
  62. $dom = $this->html5->loadHTML('<!doctype html><html lang="en"><body>foo</body></html>');
  63. $stream = fopen('php://temp', 'w');
  64. $r = new OutputRules($stream, $this->html5->getOptions());
  65. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  66. $r->document($dom);
  67. $expected = '<!DOCTYPE html>' . PHP_EOL . '<html lang="en"><body>foo</body></html>' . PHP_EOL;
  68. $this->assertEquals($expected, stream_get_contents($stream, -1, 0));
  69. }
  70. public function testEmptyDocument()
  71. {
  72. $dom = $this->html5->loadHTML('');
  73. $stream = fopen('php://temp', 'w');
  74. $r = new OutputRules($stream, $this->html5->getOptions());
  75. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  76. $r->document($dom);
  77. $expected = '<!DOCTYPE html>' . PHP_EOL;
  78. $this->assertEquals($expected, stream_get_contents($stream, -1, 0));
  79. }
  80. public function testDoctype()
  81. {
  82. $dom = $this->html5->loadHTML('<!doctype html><html lang="en"><body>foo</body></html>');
  83. $stream = fopen('php://temp', 'w');
  84. $r = new OutputRules($stream, $this->html5->getOptions());
  85. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  86. $m = $this->getProtectedMethod('doctype');
  87. $m->invoke($r, 'foo');
  88. $this->assertEquals('<!DOCTYPE html>' . PHP_EOL, stream_get_contents($stream, -1, 0));
  89. }
  90. public function testElement()
  91. {
  92. $dom = $this->html5->loadHTML(
  93. '<!doctype html>
  94. <html lang="en">
  95. <body>
  96. <div id="foo" class="bar baz">foo bar baz</div>
  97. <svg width="150" height="100" viewBox="0 0 3 2">
  98. <rect width="1" height="2" x="0" fill="#008d46" />
  99. <rect width="1" height="2" x="1" fill="#ffffff" />
  100. <rect width="1" height="2" x="2" fill="#d2232c" />
  101. </svg>
  102. </body>
  103. </html>');
  104. $stream = fopen('php://temp', 'w');
  105. $r = new OutputRules($stream, $this->html5->getOptions());
  106. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  107. $list = $dom->getElementsByTagName('div');
  108. $r->element($list->item(0));
  109. $this->assertEquals('<div id="foo" class="bar baz">foo bar baz</div>', stream_get_contents($stream, -1, 0));
  110. }
  111. public function testSerializeWithNamespaces()
  112. {
  113. $this->html5 = $this->getInstance(array(
  114. 'xmlNamespaces' => true,
  115. ));
  116. $source = '
  117. <!DOCTYPE html>
  118. <html><body id="body" xmlns:x="http://www.prefixed.com">
  119. <a id="bar1" xmlns="http://www.prefixed.com/bar1">
  120. <b id="bar4" xmlns="http://www.prefixed.com/bar4"><x:prefixed id="prefixed">xy</x:prefixed></b>
  121. </a>
  122. <svg id="svg">svg</svg>
  123. <c id="bar2" xmlns="http://www.prefixed.com/bar2"></c>
  124. <div id="div"></div>
  125. <d id="bar3"></d>
  126. <xn:d id="bar5" xmlns:xn="http://www.prefixed.com/xn" xmlns="http://www.prefixed.com/bar5_x"><x id="bar5_x">y</x></xn:d>
  127. </body>
  128. </html>';
  129. $dom = $this->html5->loadHTML($source, array(
  130. 'xmlNamespaces' => true,
  131. ));
  132. $this->assertFalse($this->html5->hasErrors(), print_r($this->html5->getErrors(), 1));
  133. $stream = fopen('php://temp', 'w');
  134. $r = new OutputRules($stream, $this->html5->getOptions());
  135. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  136. $t->walk();
  137. $rendered = stream_get_contents($stream, -1, 0);
  138. $clear = function ($s) {
  139. return trim(preg_replace('/[\s]+/', ' ', $s));
  140. };
  141. $this->assertEquals($clear($source), $clear($rendered));
  142. }
  143. public function testElementWithScript()
  144. {
  145. $dom = $this->html5->loadHTML(
  146. '<!doctype html>
  147. <html lang="en">
  148. <head>
  149. <script>
  150. var $jQ = jQuery.noConflict();
  151. // Use jQuery via $jQ(...)
  152. $jQ(document).ready(function () {
  153. $jQ("#mktFrmSubmit").wrap("<div class=\'buttonSubmit\'></div>");
  154. $jQ(".buttonSubmit").prepend("<span></span>");
  155. });
  156. </script>
  157. </head>
  158. <body>
  159. <div id="foo" class="bar baz">foo bar baz</div>
  160. </body>
  161. </html>');
  162. $stream = fopen('php://temp', 'w');
  163. $r = new OutputRules($stream, $this->html5->getOptions());
  164. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  165. $script = $dom->getElementsByTagName('script');
  166. $r->element($script->item(0));
  167. $this->assertEquals(
  168. '<script>
  169. var $jQ = jQuery.noConflict();
  170. // Use jQuery via $jQ(...)
  171. $jQ(document).ready(function () {
  172. $jQ("#mktFrmSubmit").wrap("<div class=\'buttonSubmit\'></div>");
  173. $jQ(".buttonSubmit").prepend("<span></span>");
  174. });
  175. </script>', stream_get_contents($stream, -1, 0));
  176. }
  177. public function testElementWithStyle()
  178. {
  179. $dom = $this->html5->loadHTML(
  180. '<!doctype html>
  181. <html lang="en">
  182. <head>
  183. <style>
  184. body > .bar {
  185. display: none;
  186. }
  187. </style>
  188. </head>
  189. <body>
  190. <div id="foo" class="bar baz">foo bar baz</div>
  191. </body>
  192. </html>');
  193. $stream = fopen('php://temp', 'w');
  194. $r = new OutputRules($stream, $this->html5->getOptions());
  195. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  196. $style = $dom->getElementsByTagName('style');
  197. $r->element($style->item(0));
  198. $this->assertEquals('<style>
  199. body > .bar {
  200. display: none;
  201. }
  202. </style>', stream_get_contents($stream, -1, 0));
  203. }
  204. public function testOpenTag()
  205. {
  206. $dom = $this->html5->loadHTML('<!doctype html>
  207. <html lang="en">
  208. <body>
  209. <div id="foo" class="bar baz">foo bar baz</div>
  210. </body>
  211. </html>');
  212. $stream = fopen('php://temp', 'w');
  213. $r = new OutputRules($stream, $this->html5->getOptions());
  214. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  215. $list = $dom->getElementsByTagName('div');
  216. $m = $this->getProtectedMethod('openTag');
  217. $m->invoke($r, $list->item(0));
  218. $this->assertEquals('<div id="foo" class="bar baz">', stream_get_contents($stream, -1, 0));
  219. }
  220. public function testCData()
  221. {
  222. $dom = $this->html5->loadHTML('<!doctype html>
  223. <html lang="en">
  224. <body>
  225. <div><![CDATA[bar]]></div>
  226. </body>
  227. </html>');
  228. $stream = fopen('php://temp', 'w');
  229. $r = new OutputRules($stream, $this->html5->getOptions());
  230. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  231. $list = $dom->getElementsByTagName('div');
  232. $r->cdata($list->item(0)->childNodes->item(0));
  233. $this->assertEquals('<![CDATA[bar]]>', stream_get_contents($stream, -1, 0));
  234. $dom = $this->html5->loadHTML('<!doctype html>
  235. <html lang="en">
  236. <body>
  237. <div id="foo"></div>
  238. </body>
  239. </html>');
  240. $dom->getElementById('foo')->appendChild(new \DOMCdataSection(']]>Foo<[![CDATA test ]]>'));
  241. $stream = fopen('php://temp', 'w');
  242. $r = new OutputRules($stream, $this->html5->getOptions());
  243. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  244. $list = $dom->getElementsByTagName('div');
  245. $r->cdata($list->item(0)->childNodes->item(0));
  246. $this->assertEquals('<![CDATA[]]]]><![CDATA[>Foo<[![CDATA test ]]]]><![CDATA[>]]>', stream_get_contents($stream, -1, 0));
  247. }
  248. public function testComment()
  249. {
  250. $dom = $this->html5->loadHTML('<!doctype html>
  251. <html lang="en">
  252. <body>
  253. <div><!-- foo --></div>
  254. </body>
  255. </html>');
  256. $stream = fopen('php://temp', 'w');
  257. $r = new OutputRules($stream, $this->html5->getOptions());
  258. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  259. $list = $dom->getElementsByTagName('div');
  260. $r->comment($list->item(0)->childNodes->item(0));
  261. $this->assertEquals('<!-- foo -->', stream_get_contents($stream, -1, 0));
  262. $dom = $this->html5->loadHTML('<!doctype html>
  263. <html lang="en">
  264. <body>
  265. <div id="foo"></div>
  266. </body>
  267. </html>');
  268. $dom->getElementById('foo')->appendChild(new \DOMComment('<!-- --> --> Foo -->'));
  269. $stream = fopen('php://temp', 'w');
  270. $r = new OutputRules($stream, $this->html5->getOptions());
  271. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  272. $list = $dom->getElementsByTagName('div');
  273. $r->comment($list->item(0)->childNodes->item(0));
  274. // Could not find more definitive guidelines on what this should be. Went with
  275. // what the HTML5 spec says and what \DOMDocument::saveXML() produces.
  276. $this->assertEquals('<!--<!-- --> --> Foo -->-->', stream_get_contents($stream, -1, 0));
  277. }
  278. public function testText()
  279. {
  280. $dom = $this->html5->loadHTML('<!doctype html>
  281. <html lang="en">
  282. <head>
  283. <script>baz();</script>
  284. </head>
  285. </html>');
  286. $stream = fopen('php://temp', 'w');
  287. $r = new OutputRules($stream, $this->html5->getOptions());
  288. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  289. $list = $dom->getElementsByTagName('script');
  290. $r->text($list->item(0)->childNodes->item(0));
  291. $this->assertEquals('baz();', stream_get_contents($stream, -1, 0));
  292. $dom = $this->html5->loadHTML('<!doctype html>
  293. <html lang="en">
  294. <head id="foo"></head>
  295. </html>');
  296. $foo = $dom->getElementById('foo');
  297. $foo->appendChild(new \DOMText('<script>alert("hi");</script>'));
  298. $stream = fopen('php://temp', 'w');
  299. $r = new OutputRules($stream, $this->html5->getOptions());
  300. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  301. $r->text($foo->firstChild);
  302. $this->assertEquals('&lt;script&gt;alert("hi");&lt;/script&gt;', stream_get_contents($stream, -1, 0));
  303. }
  304. public function testNl()
  305. {
  306. list($o, $s) = $this->getOutputRules();
  307. $m = $this->getProtectedMethod('nl');
  308. $m->invoke($o);
  309. $this->assertEquals(PHP_EOL, stream_get_contents($s, -1, 0));
  310. }
  311. public function testWr()
  312. {
  313. list($o, $s) = $this->getOutputRules();
  314. $m = $this->getProtectedMethod('wr');
  315. $m->invoke($o, 'foo');
  316. $this->assertEquals('foo', stream_get_contents($s, -1, 0));
  317. }
  318. public function getEncData()
  319. {
  320. return array(
  321. array(
  322. false,
  323. '&\'<>"',
  324. '&amp;\'&lt;&gt;"',
  325. '&amp;&apos;&lt;&gt;&quot;',
  326. ),
  327. array(
  328. false,
  329. 'This + is. a < test',
  330. 'This + is. a &lt; test',
  331. 'This &plus; is&period; a &lt; test',
  332. ),
  333. array(
  334. false,
  335. '.+#',
  336. '.+#',
  337. '&period;&plus;&num;',
  338. ),
  339. array(
  340. true,
  341. '.+#\'',
  342. '.+#\'',
  343. '&period;&plus;&num;&apos;',
  344. ),
  345. array(
  346. true,
  347. '&".<',
  348. '&amp;&quot;.<',
  349. '&amp;&quot;&period;&lt;',
  350. ),
  351. array(
  352. true,
  353. '&\'<>"',
  354. '&amp;\'<>&quot;',
  355. '&amp;&apos;&lt;&gt;&quot;',
  356. ),
  357. array(
  358. true,
  359. "\xc2\xa0\"'",
  360. '&nbsp;&quot;\'',
  361. '&nbsp;&quot;&apos;',
  362. ),
  363. );
  364. }
  365. /**
  366. * Test basic encoding of text.
  367. *
  368. * @dataProvider getEncData
  369. */
  370. public function testEnc($isAttribute, $test, $expected, $expectedEncoded)
  371. {
  372. list($o, $s) = $this->getOutputRules();
  373. $m = $this->getProtectedMethod('enc');
  374. $this->assertEquals($expected, $m->invoke($o, $test, $isAttribute));
  375. list($o, $s) = $this->getOutputRules(array(
  376. 'encode_entities' => true,
  377. ));
  378. $m = $this->getProtectedMethod('enc');
  379. $this->assertEquals($expectedEncoded, $m->invoke($o, $test, $isAttribute));
  380. }
  381. /**
  382. * Test basic encoding of text.
  383. *
  384. * @dataProvider getEncData
  385. */
  386. public function testEscape($isAttribute, $test, $expected, $expectedEncoded)
  387. {
  388. list($o, $s) = $this->getOutputRules();
  389. $m = $this->getProtectedMethod('escape');
  390. $this->assertEquals($expected, $m->invoke($o, $test, $isAttribute));
  391. }
  392. public function booleanAttributes()
  393. {
  394. return array(
  395. array('<img alt="" ismap>'),
  396. array('<img alt="">'),
  397. array('<input type="radio" readonly>'),
  398. array('<input type="radio" checked disabled>'),
  399. array('<input type="checkbox" checked disabled>'),
  400. array('<input type="radio" value="" checked disabled>'),
  401. array('<div data-value=""></div>'),
  402. array('<select disabled></select>'),
  403. array('<div ng-app></div>'),
  404. array('<script defer></script>'),
  405. );
  406. }
  407. /**
  408. * @dataProvider booleanAttributes
  409. */
  410. public function testBooleanAttrs($html)
  411. {
  412. $dom = $this->html5->loadHTML('<!doctype html><html lang="en"><body>' . $html . '</body></html>');
  413. $stream = fopen('php://temp', 'w');
  414. $r = new OutputRules($stream, $this->html5->getOptions());
  415. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  416. $node = $dom->getElementsByTagName('body')->item(0)->firstChild;
  417. $m = $this->getProtectedMethod('attrs');
  418. $m->invoke($r, $node);
  419. $content = stream_get_contents($stream, -1, 0);
  420. $html = preg_replace('~<[a-z]+(.*)></[a-z]+>~', '\1', $html);
  421. $html = preg_replace('~<[a-z]+(.*)/?>~', '\1', $html);
  422. $this->assertEquals($content, $html);
  423. }
  424. public function testAttrs()
  425. {
  426. $dom = $this->html5->loadHTML('<!doctype html>
  427. <html lang="en">
  428. <body>
  429. <div id="foo" class="bar baz">foo bar baz</div>
  430. </body>
  431. </html>');
  432. $stream = fopen('php://temp', 'w');
  433. $r = new OutputRules($stream, $this->html5->getOptions());
  434. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  435. $list = $dom->getElementsByTagName('div');
  436. $m = $this->getProtectedMethod('attrs');
  437. $m->invoke($r, $list->item(0));
  438. $content = stream_get_contents($stream, -1, 0);
  439. $this->assertEquals(' id="foo" class="bar baz"', $content);
  440. }
  441. public function testSvg()
  442. {
  443. $dom = $this->html5->loadHTML(
  444. '<!doctype html>
  445. <html lang="en">
  446. <body>
  447. <div id="foo" class="bar baz">foo bar baz</div>
  448. <svg width="150" height="100" viewBox="0 0 3 2">
  449. <rect width="1" height="2" x="0" fill="#008d46" />
  450. <rect width="1" height="2" x="1" fill="#ffffff" />
  451. <rect width="1" height="2" x="2" fill="#d2232c" />
  452. <rect id="Bar" x="300" y="100" width="300" height="100" fill="rgb(255,255,0)">
  453. <animate attributeName="x" attributeType="XML" begin="0s" dur="9s" fill="freeze" from="300" to="0" />
  454. </rect>
  455. </svg>
  456. </body>
  457. </html>');
  458. $stream = fopen('php://temp', 'w');
  459. $r = new OutputRules($stream, $this->html5->getOptions());
  460. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  461. $list = $dom->getElementsByTagName('svg');
  462. $r->element($list->item(0));
  463. $contents = stream_get_contents($stream, -1, 0);
  464. $this->assertRegExp('|<svg width="150" height="100" viewBox="0 0 3 2">|', $contents);
  465. $this->assertRegExp('|<rect width="1" height="2" x="0" fill="#008d46" />|', $contents);
  466. $this->assertRegExp('|<rect id="Bar" x="300" y="100" width="300" height="100" fill="rgb\(255,255,0\)">|', $contents);
  467. }
  468. public function testMath()
  469. {
  470. $dom = $this->html5->loadHTML(
  471. '<!doctype html>
  472. <html lang="en">
  473. <body>
  474. <div id="foo" class="bar baz">foo bar baz</div>
  475. <math>
  476. <mi>x</mi>
  477. <csymbol definitionURL="http://www.example.com/mathops/multiops.html#plusminus">
  478. <mo>&PlusMinus;</mo>
  479. </csymbol>
  480. <mi>y</mi>
  481. </math>
  482. </body>
  483. </html>');
  484. $stream = fopen('php://temp', 'w');
  485. $r = new OutputRules($stream, $this->html5->getOptions());
  486. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  487. $list = $dom->getElementsByTagName('math');
  488. $r->element($list->item(0));
  489. $content = stream_get_contents($stream, -1, 0);
  490. $this->assertRegExp('|<math>|', $content);
  491. $this->assertRegExp('|<csymbol definitionURL="http://www.example.com/mathops/multiops.html#plusminus">|', $content);
  492. }
  493. public function testProcessorInstruction()
  494. {
  495. $dom = $this->html5->loadHTMLFragment('<?foo bar ?>');
  496. $stream = fopen('php://temp', 'w');
  497. $r = new OutputRules($stream, $this->html5->getOptions());
  498. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  499. $r->processorInstruction($dom->firstChild);
  500. $content = stream_get_contents($stream, -1, 0);
  501. $this->assertRegExp('|<\?foo bar \?>|', $content);
  502. }
  503. public function testAddressTag()
  504. {
  505. $dom = $this->html5->loadHTML(
  506. '<!doctype html>
  507. <html lang="en">
  508. <body>
  509. <address>
  510. <a href="../People/Raggett/">Dave Raggett</a>,
  511. <a href="../People/Arnaud/">Arnaud Le Hors</a>,
  512. contact persons for the <a href="Activity">W3C HTML Activity</a>
  513. </address>
  514. </body>
  515. </html>');
  516. $stream = fopen('php://temp', 'w');
  517. $r = new OutputRules($stream, $this->html5->getOptions());
  518. $t = new Traverser($dom, $stream, $r, $this->html5->getOptions());
  519. $list = $dom->getElementsByTagName('address');
  520. $r->element($list->item(0));
  521. $contents = stream_get_contents($stream, -1, 0);
  522. $this->assertRegExp('|<address>|', $contents);
  523. $this->assertRegExp('|<a href="../People/Raggett/">Dave Raggett</a>,|', $contents);
  524. $this->assertRegExp('|<a href="../People/Arnaud/">Arnaud Le Hors</a>,|', $contents);
  525. $this->assertRegExp('|contact persons for the <a href="Activity">W3C HTML Activity</a>|', $contents);
  526. $this->assertRegExp('|</address>|', $contents);
  527. }
  528. /**
  529. * Ensure direct DOM manipulation doesn't break TEXT_RAW elements (iframe, script, etc...).
  530. */
  531. public function testHandlingInvalidRawContent()
  532. {
  533. $dom = $this->html5->loadHTML(
  534. '<!doctype html>
  535. <html lang="en" id="base">
  536. <body>
  537. <script id="template" type="x-tmpl-mustache">
  538. <h1>Hello!</h1>
  539. </script>
  540. </body>
  541. </html>');
  542. $badNode = $dom->createElement('p', 'Bar');
  543. // modify the content of the TEXT_RAW element: <script id="template"> appending dom nodes
  544. $styleElement = $dom->getElementById('template');
  545. $styleElement->appendChild($badNode);
  546. $contents = $this->html5->saveHTML($dom);
  547. $this->assertTrue(false !== strpos($contents, '<script id="template" type="x-tmpl-mustache">
  548. <h1>Hello!</h1>
  549. <p>Bar</p></script>'));
  550. }
  551. }