Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 

537 wiersze
14 KiB

  1. /* global console */
  2. var test = require('tape');
  3. var HTML = require('../index');
  4. test('parse', function (t) {
  5. var html = '<div class="oh"><p></p></div>';
  6. var parsed = HTML.parse(html);
  7. t.deepEqual(parsed, [{
  8. type: 'tag',
  9. name: 'div',
  10. attrs: {
  11. class: 'oh'
  12. },
  13. voidElement: false,
  14. children: [
  15. {
  16. type: 'tag',
  17. name: 'p',
  18. attrs: {},
  19. children: [],
  20. voidElement: false
  21. }
  22. ]
  23. }]);
  24. t.equal(html, HTML.stringify(parsed));
  25. html = '<div class="oh"><p>hi</p></div>';
  26. parsed = HTML.parse(html);
  27. t.deepEqual(parsed, [{
  28. type: 'tag',
  29. name: 'div',
  30. attrs: {
  31. class: 'oh'
  32. },
  33. voidElement: false,
  34. children: [
  35. {
  36. type: 'tag',
  37. name: 'p',
  38. attrs: {},
  39. voidElement: false,
  40. children: [
  41. {
  42. type: 'text',
  43. content: 'hi'
  44. }
  45. ]
  46. }
  47. ]
  48. }]);
  49. t.equal(html, HTML.stringify(parsed));
  50. html = '<div>oh <strong>hello</strong> there! How are <span>you</span>?</div>';
  51. parsed = HTML.parse(html);
  52. t.deepEqual(parsed, [{
  53. type: 'tag',
  54. name: 'div',
  55. attrs: {},
  56. voidElement: false,
  57. children: [
  58. {
  59. type: 'text',
  60. content: 'oh '
  61. },
  62. {
  63. type: 'tag',
  64. name: 'strong',
  65. attrs: {},
  66. voidElement: false,
  67. children: [
  68. {
  69. type: 'text',
  70. content: 'hello'
  71. }
  72. ]
  73. },
  74. {
  75. type: 'text',
  76. content: ' there! How are '
  77. },
  78. {
  79. type: 'tag',
  80. name: 'span',
  81. attrs: {},
  82. voidElement: false,
  83. children: [
  84. {
  85. type: 'text',
  86. content: 'you'
  87. }
  88. ]
  89. },
  90. {
  91. type: 'text',
  92. content: '?'
  93. }
  94. ]
  95. }]);
  96. t.equal(html, HTML.stringify(parsed));
  97. html = '<div class="handles multiple classes" and="attributes"></div>';
  98. parsed = HTML.parse(html);
  99. t.deepEqual(parsed, [{
  100. type: 'tag',
  101. name: 'div',
  102. attrs: {
  103. class: 'handles multiple classes',
  104. and: 'attributes'
  105. },
  106. voidElement: false,
  107. children: []
  108. }]);
  109. t.equal(html, HTML.stringify(parsed));
  110. html = '<div class=\'handles\' other=47 and="attributes"></div>';
  111. parsed = HTML.parse(html);
  112. t.deepEqual(parsed, [{
  113. type: 'tag',
  114. name: 'div',
  115. attrs: {
  116. class: 'handles',
  117. other: '47',
  118. and: 'attributes'
  119. },
  120. voidElement: false,
  121. children: []
  122. }]);
  123. t.equal(HTML.stringify(parsed), '<div class="handles" other="47" and="attributes"></div>');
  124. html = '<div-custom class="oh"><my-component some="thing"><p>should be ignored</p></my-component></div-custom>';
  125. parsed = HTML.parse(html, {
  126. components: {
  127. 'my-component': 'something'
  128. }
  129. });
  130. t.deepEqual(parsed, [{
  131. type: 'tag',
  132. name: 'div-custom',
  133. attrs: {
  134. class: 'oh'
  135. },
  136. voidElement: false,
  137. children: [
  138. {
  139. type: 'component',
  140. name: 'my-component',
  141. attrs: {
  142. some: 'thing'
  143. },
  144. voidElement: false,
  145. children: []
  146. }
  147. ]
  148. }], 'should not include children of registered components in AST');
  149. html = '<div><my-component thing="one">ok</my-component><my-component thing="two">ok</my-component></div>';
  150. parsed = HTML.parse(html, {
  151. components: {
  152. 'my-component': 'something'
  153. }
  154. });
  155. t.deepEqual(parsed, [{
  156. type: 'tag',
  157. name: 'div',
  158. attrs: {},
  159. voidElement: false,
  160. children: [
  161. {
  162. type: 'component',
  163. name: 'my-component',
  164. attrs: {
  165. thing: 'one'
  166. },
  167. voidElement: false,
  168. children: []
  169. },
  170. {
  171. type: 'component',
  172. name: 'my-component',
  173. attrs: {
  174. thing: 'two'
  175. },
  176. voidElement: false,
  177. children: []
  178. }
  179. ]
  180. }]);
  181. html = '<div><img></div>';
  182. parsed = HTML.parse(html);
  183. t.deepEqual(parsed, [{
  184. type: 'tag',
  185. name: 'div',
  186. attrs: {},
  187. voidElement: false,
  188. children: [
  189. {
  190. type: 'tag',
  191. name: 'img',
  192. attrs: {},
  193. voidElement: true,
  194. children: []
  195. }
  196. ]
  197. }], 'should handle unclosed void elements');
  198. t.equal(HTML.stringify(parsed), '<div><img/></div>');
  199. html = '<div></div><img>';
  200. parsed = HTML.parse(html);
  201. t.deepEqual(parsed, [
  202. {
  203. type: 'tag',
  204. name: 'div',
  205. attrs: {},
  206. voidElement: false,
  207. children: []
  208. },
  209. {
  210. type: 'tag',
  211. name: 'img',
  212. attrs: {},
  213. voidElement: true,
  214. children: []
  215. }
  216. ], 'should handle multiple root nodes');
  217. t.equal(HTML.stringify(parsed), '<div></div><img/>');
  218. html = '<div><void-web-component/></div>';
  219. parsed = HTML.parse(html);
  220. t.deepEqual(parsed, [{
  221. type: 'tag',
  222. name: 'div',
  223. attrs: {},
  224. voidElement: false,
  225. children: [
  226. {
  227. type: 'tag',
  228. name: 'void-web-component',
  229. attrs: {},
  230. voidElement: true,
  231. children: []
  232. }
  233. ]
  234. }], 'should handle custom void tags if self-closing');
  235. html = '<div><void-registered-component/></div>';
  236. parsed = HTML.parse(html, {components: {'void-registered-component': true}});
  237. t.deepEqual(parsed, [{
  238. type: 'tag',
  239. name: 'div',
  240. attrs: {},
  241. voidElement: false,
  242. children: [
  243. {
  244. type: 'component',
  245. name: 'void-registered-component',
  246. attrs: {},
  247. voidElement: true,
  248. children: []
  249. }
  250. ]
  251. }], 'should handle registered void tags if self-closing');
  252. html = '<div> 9 <input type="text"/> 10 </div>';
  253. parsed = HTML.parse(html);
  254. t.deepEqual(parsed, [{
  255. type: 'tag',
  256. name: 'div',
  257. attrs: {},
  258. voidElement: false,
  259. children: [
  260. { type: 'text', content: ' 9 ' },
  261. {
  262. type: 'tag',
  263. name: 'input',
  264. attrs: {
  265. type: 'text'
  266. },
  267. children: [],
  268. voidElement: true,
  269. },
  270. { type: 'text', content: ' 10 ' },
  271. ]
  272. }], 'should not give voidElements children');
  273. html = '<div></div>\n';
  274. parsed = HTML.parse(html);
  275. t.deepEqual(parsed, [{
  276. type: 'tag',
  277. name: 'div',
  278. attrs: {},
  279. voidElement: false,
  280. children: []
  281. }], 'should not explode on trailing whitespace');
  282. html = '<div>Hi</div> There ';
  283. parsed = HTML.parse(html);
  284. t.deepEqual(parsed, [{
  285. type: 'tag',
  286. name: 'div',
  287. attrs: {},
  288. voidElement: false,
  289. children: [
  290. { type: 'text', content: 'Hi' }
  291. ]
  292. },{
  293. type: 'text', content: ' There '
  294. }], 'should handle trailing text nodes at the top-level');
  295. html = '<div>Hi</div> There <span>something</span> <a></a>else ';
  296. parsed = HTML.parse(html);
  297. t.deepEqual(parsed, [{
  298. type: 'tag',
  299. name: 'div',
  300. attrs: {},
  301. voidElement: false,
  302. children: [
  303. { type: 'text', content: 'Hi' }
  304. ]
  305. },{
  306. type: 'text', content: ' There '
  307. },{
  308. type: 'tag',
  309. name: 'span',
  310. attrs: {},
  311. voidElement: false,
  312. children: [
  313. { type: 'text', content: 'something' }
  314. ]
  315. },{
  316. type: 'text',
  317. content: ' '
  318. },
  319. {
  320. type: 'tag',
  321. name: 'a',
  322. attrs: {},
  323. voidElement: false,
  324. children: []
  325. },{
  326. type: 'text', content: 'else '
  327. }], 'should handle text nodes in the middle of tags at the top-level');
  328. html = '\n<div> <span>Hi!</span> </div>\n';
  329. parsed = HTML.parse(html);
  330. t.deepEqual(parsed, [{
  331. type: 'tag',
  332. name: 'div',
  333. attrs: {},
  334. voidElement: false,
  335. children: [
  336. { type: 'text', content: ' '},
  337. {
  338. type: 'tag',
  339. name: 'span',
  340. attrs: {},
  341. voidElement: false,
  342. children: [
  343. { type: 'text', content: 'Hi!' }
  344. ]
  345. },
  346. { type: 'text', content: ' '}
  347. ]
  348. }], 'should trim whitespace from the beginning and end of the parsed nodes');
  349. html = '<div>Hi</div>\n\n <span>There</span> \t <div>\n\t</div>';
  350. parsed = HTML.parse(html);
  351. t.deepEqual(parsed, [{
  352. type: 'tag',
  353. name: 'div',
  354. attrs: {},
  355. voidElement: false,
  356. children: [
  357. { type: 'text', content: 'Hi' }
  358. ]
  359. },{
  360. type: 'text',
  361. content: ' '
  362. },
  363. {
  364. type: 'tag',
  365. name: 'span',
  366. attrs: {},
  367. voidElement: false,
  368. children: [
  369. { type: 'text', content: 'There' }
  370. ]
  371. },{
  372. type: 'text',
  373. content: ' '
  374. },{
  375. type: 'tag',
  376. name: 'div',
  377. attrs: {},
  378. voidElement: false,
  379. children: [
  380. { type: 'text', content: ' ' }
  381. ]
  382. }], 'should collapse whitespace');
  383. // See https://www.w3.org/TR/html4/struct/text.html#h-9.1
  384. html = '<div>Hi</div>\n\n <span>There</span> \t <iframe>\n\t</iframe>';
  385. parsed = HTML.parse(html, { ignoreWhitespace: true });
  386. t.deepEqual(parsed, [{
  387. type: 'tag',
  388. name: 'div',
  389. attrs: {},
  390. voidElement: false,
  391. children: [
  392. { type: 'text', content: 'Hi' }
  393. ]
  394. },{
  395. type: 'tag',
  396. name: 'span',
  397. attrs: {},
  398. voidElement: false,
  399. children: [
  400. { type: 'text', content: 'There' }
  401. ]
  402. },{
  403. type: 'tag',
  404. name: 'iframe',
  405. attrs: {},
  406. voidElement: false,
  407. children: []
  408. }], 'should remove text nodes that are nothing but whitespace if the ignoreWhitespace option is passed');
  409. html = '<!--\n\t<style type="text/css">\n\t\t.header {\n\t\t\tfont-size: 14px;\n\t\t}\n\t</style>\n\n-->\n<div>Hi</div>';
  410. parsed = HTML.parse(html);
  411. t.deepEqual(parsed, [{
  412. type: 'tag',
  413. name: 'div',
  414. attrs: {},
  415. voidElement: false,
  416. children: [
  417. { type: 'text', content: 'Hi'}
  418. ]
  419. }], 'should ignore HTML comments');
  420. html = '<div>Hi <!-- I\'m a nested comment! with a <span></span> -->there<strong>!</strong></div><span><!--test--></span>';
  421. parsed = HTML.parse(html);
  422. t.deepEqual(parsed, [{
  423. type: 'tag',
  424. name: 'div',
  425. attrs: {},
  426. voidElement: false,
  427. children: [
  428. { type: 'text', content: 'Hi '},
  429. { type: 'text', content: 'there'},
  430. {
  431. type: 'tag',
  432. name: 'strong',
  433. attrs: {},
  434. voidElement: false,
  435. children: [{ type: 'text', content: '!'}]
  436. }
  437. ]
  438. },{
  439. type: 'tag',
  440. name: 'span',
  441. attrs: {},
  442. voidElement: false,
  443. children: []
  444. }], 'should ignore nested HTML comments');
  445. html = 'Hello, world!';
  446. parsed = HTML.parse(html);
  447. t.deepEqual(parsed, [{
  448. type: 'text',
  449. content: 'Hello, world!'
  450. }], 'should handle just text');
  451. t.end();
  452. });
  453. test('simple speed sanity check', function (t) {
  454. var i = 100000;
  455. var groupSize = 1000;
  456. var waitLoopSize = 10000000;
  457. var groups = i / groupSize;
  458. var html = '<html><head><title>Some page</title></head><body class="hey there"><img src="someURL"><h3>Hey, we need content</h3><br></body></html>';
  459. var parse = HTML.parse;
  460. var times = [];
  461. var count;
  462. var waitCount;
  463. var total = 0;
  464. var start, stepAverage;
  465. console.log('running ' + i + ' iterations...');
  466. while(i--) {
  467. count = groupSize;
  468. // grab groups
  469. if (i % count === 0) {
  470. start = Date.now();
  471. while(count--) {
  472. parse(html);
  473. }
  474. var diff = Date.now() - start;
  475. stepAverage = diff/groupSize;
  476. console.log('group ' + (groups - (i / groupSize)) + ': ' + stepAverage);
  477. times.push(stepAverage);
  478. total += stepAverage;
  479. waitCount = waitLoopSize;
  480. // forcing a bit of a pause between tests
  481. while(waitCount--) {}
  482. }
  483. }
  484. // trim off first
  485. // it's always a slower outlier
  486. // with higher variability that
  487. // makes it harder to find differences
  488. times.shift();
  489. var max = Math.max.apply(null, times);
  490. var min = Math.min.apply(null, times);
  491. var average = total / times.length;
  492. console.log('max', max);
  493. console.log('min', min);
  494. console.log('avg', average);
  495. t.end();
  496. });