Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

644 řádky
13KB

  1. module('Interpreter');
  2. test("Argument validation", function() {
  3. expect(4);
  4. equals(Mustache.to_html(undefined), '', 'No parameters');
  5. equals(Mustache.to_html('{{hi}}'), '', ' No View or Partials');
  6. equals(Mustache.to_html('{{hi}}', {hi:'Hi.'}), 'Hi.', 'No Partials');
  7. equals(Mustache.to_html('{{>hi}}', undefined, {hi:'{{p}}'}), '', 'Partial but no view');
  8. });
  9. test("Parser", function() {
  10. expect(3);
  11. // matches whitespace_partial.html
  12. equals(
  13. Mustache.to_html(
  14. '<h1>{{ greeting }}</h1>\n{{> partial }}\n<h3>{{ farewell }}</h3>',
  15. {
  16. greeting: function() {
  17. return "Welcome";
  18. },
  19. farewell: function() {
  20. return "Fair enough, right?";
  21. },
  22. partial: {
  23. name: "Chris",
  24. value: 10000,
  25. taxed_value: function() {
  26. return this.value - (this.value * 0.4);
  27. },
  28. in_ca: true
  29. }
  30. },
  31. {partial:'Hello {{ name}}\nYou have just won ${{value }}!\n{{# in_ca }}\nWell, ${{ taxed_value }}, after taxes.\n{{/ in_ca }}\n'}
  32. ),
  33. '<h1>Welcome</h1>\nHello Chris\nYou have just won $10000!\n\nWell, $6000, after taxes.\n\n\n<h3>Fair enough, right?</h3>',
  34. 'Whitespace in Tag names'
  35. );
  36. equals(
  37. Mustache.to_html(
  38. '{{tag1}}\n\n\n{{tag2}}\n',
  39. { tag1: 'Hello', tag2: 'World' },
  40. {}
  41. ),
  42. 'Hello\n\n\nWorld\n',
  43. 'Preservation of white space'
  44. );
  45. try {
  46. Mustache.to_html(
  47. '{{=tag1}}',
  48. { tag1: 'Hello' },
  49. {}
  50. );
  51. ok(false);
  52. } catch (e) {
  53. equals(e.message, 'Unexpected end of document.');
  54. }
  55. });
  56. test("Basic Variables", function() {
  57. expect(4);
  58. // matches escaped.html
  59. equals(
  60. Mustache.to_html(
  61. '<h1>{{title}}</h1>\nBut not {{entities}}.\n',
  62. {
  63. title: function() {
  64. return "Bear > Shark";
  65. },
  66. entities: "&quot;"
  67. },
  68. {}
  69. ),
  70. '<h1>Bear &gt; Shark</h1>\nBut not &amp;quot;.\n',
  71. 'HTML Escaping'
  72. );
  73. // matches apostrophe.html (except in this implementation, apostrophes are not escaped.
  74. equals(
  75. Mustache.to_html(
  76. '{{apos}}{{control}}',
  77. { apos: '\'', control: 'X' },
  78. {}
  79. ),
  80. '\'X',
  81. 'Apostrophe escaping'
  82. );
  83. // matches null_string.html
  84. equals(
  85. Mustache.to_html(
  86. 'Hello {{name}}\nglytch {{glytch}}\nbinary {{binary}}\nvalue {{value}}\nnumeric {{numeric}}',
  87. {
  88. name: "Elise",
  89. glytch: true,
  90. binary: false,
  91. value: null,
  92. numeric: function() {
  93. return NaN;
  94. }
  95. },
  96. {}
  97. ),
  98. 'Hello Elise\nglytch true\nbinary false\nvalue \nnumeric NaN',
  99. 'Different variable types'
  100. );
  101. // matches two_in_a_row.html
  102. equals(
  103. Mustache.to_html(
  104. '{{greeting}}, {{name}}!',
  105. {
  106. name: "Joe",
  107. greeting: "Welcome"
  108. },
  109. {}
  110. ),
  111. 'Welcome, Joe!'
  112. );
  113. });
  114. test("'{' or '&' (Unescaped Variable)", function() {
  115. expect(2);
  116. // matches unescaped.html
  117. equals(
  118. Mustache.to_html(
  119. '<h1>{{{title}}}</h1>',
  120. {
  121. title: function() {
  122. return "Bear > Shark";
  123. }
  124. },
  125. {}
  126. ),
  127. '<h1>Bear > Shark</h1>',
  128. '{ character'
  129. );
  130. equals(
  131. Mustache.to_html(
  132. '<h1>{{&title}}</h1>',
  133. {
  134. title: function() {
  135. return "Bear > Shark";
  136. }
  137. },
  138. {}
  139. ),
  140. '<h1>Bear > Shark</h1>',
  141. '& character'
  142. );
  143. });
  144. test("'#' (Sections)", function() {
  145. expect(8);
  146. // matches array_of_partials_implicit_partial.html
  147. equals(
  148. Mustache.to_html(
  149. 'Here is some stuff!\n{{#numbers}}\n{{>partial}}\n{{/numbers}}',
  150. { numbers: ['1', '2', '3', '4'] },
  151. { partial: '{{.}}' }
  152. ),
  153. 'Here is some stuff!\n\n1\n\n2\n\n3\n\n4\n',
  154. 'Array of Partials (Implicit)'
  155. );
  156. // matches array_of_partials_partial.html
  157. equals(
  158. Mustache.to_html(
  159. 'Here is some stuff!\n{{#numbers}}\n{{>partial}}\n{{/numbers}}',
  160. { numbers: [{i: '1'}, {i: '2'}, {i: '3'}, {i: '4'}] },
  161. { partial: '{{i}}' }
  162. ),
  163. 'Here is some stuff!\n\n1\n\n2\n\n3\n\n4\n',
  164. 'Array of Partials (Explicit)'
  165. );
  166. // matches array_of_strings.html
  167. equals(
  168. Mustache.to_html(
  169. '{{#array_of_strings}}{{.}} {{/array_of_strings}}',
  170. {array_of_strings: ['hello', 'world']},
  171. {}
  172. ),
  173. 'hello world ',
  174. 'Array of Strings'
  175. );
  176. // mathces higher_order_sections.html
  177. equals(
  178. Mustache.to_html(
  179. '{{#bolder}}Hi {{name}}.{{/bolder}}\n',
  180. {
  181. "name": "Tater",
  182. "helper": "To tinker?",
  183. "bolder": function() {
  184. return function(text, render) {
  185. return "<b>" + render(text) + '</b> ' + this.helper;
  186. }
  187. }
  188. },
  189. {}
  190. ),
  191. '<b>Hi Tater.</b> To tinker?\n'
  192. );
  193. // matches recursion_with_same_names.html
  194. equals(
  195. Mustache.to_html(
  196. '{{ name }}\n{{ description }}\n\n{{#terms}}\n {{name}}\n {{index}}\n{{/terms}}\n',
  197. {
  198. name: 'name',
  199. description: 'desc',
  200. terms: [
  201. {name: 't1', index: 0},
  202. {name: 't2', index: 1}
  203. ]
  204. },
  205. {}
  206. ),
  207. 'name\ndesc\n\n\n t1\n 0\n\n t2\n 1\n\n'
  208. );
  209. // matches reuse_of_enumerables.html
  210. equals(
  211. Mustache.to_html(
  212. '{{#terms}}\n {{name}}\n {{index}}\n{{/terms}}\n{{#terms}}\n {{name}}\n {{index}}\n{{/terms}}\n',
  213. {
  214. terms: [
  215. {name: 't1', index: 0},
  216. {name: 't2', index: 1}
  217. ]
  218. },
  219. {}
  220. ),
  221. '\n t1\n 0\n\n t2\n 1\n\n\n t1\n 0\n\n t2\n 1\n\n',
  222. 'Lazy match of Section and Inverted Section'
  223. );
  224. // matches section_as_context.html
  225. equals(
  226. Mustache.to_html(
  227. '{{#a_object}}\n <h1>{{title}}</h1>\n <p>{{description}}</p>\n <ul>\n {{#a_list}}\n <li>{{label}}</li>\n {{/a_list}}\n </ul>\n{{/a_object}}\n',
  228. {
  229. a_object: {
  230. title: 'this is an object',
  231. description: 'one of its attributes is a list',
  232. a_list: [{label: 'listitem1'}, {label: 'listitem2'}]
  233. }
  234. },
  235. {}
  236. ),
  237. '\n <h1>this is an object</h1>\n <p>one of its attributes is a list</p>\n <ul>\n \n <li>listitem1</li>\n \n <li>listitem2</li>\n \n </ul>\n\n',
  238. 'Lazy match of Section and Inverted Section'
  239. );
  240. // matches nesting.html
  241. equals(
  242. Mustache.to_html(
  243. '{{#foo}}\n {{#a}}\n {{b}}\n {{/a}}\n{{/foo}}',
  244. {
  245. foo: [
  246. {a: {b: 1}},
  247. {a: {b: 2}},
  248. {a: {b: 3}}
  249. ]
  250. },
  251. {}
  252. ),
  253. '\n \n 1\n \n\n \n 2\n \n\n \n 3\n \n',
  254. 'Context Nesting'
  255. );
  256. });
  257. test("'^' (Inverted Section)", function() {
  258. expect(1);
  259. // matches inverted_section.html
  260. equals(
  261. Mustache.to_html(
  262. '{{#repo}}<b>{{name}}</b>{{/repo}}\n{{^repo}}No repos :({{/repo}}\n',
  263. {
  264. "repo": []
  265. },
  266. {}
  267. ),
  268. '\nNo repos :(\n'
  269. );
  270. });
  271. test("'>' (Partials)", function() {
  272. expect(5);
  273. // matches view_partial.html
  274. equals(
  275. Mustache.to_html(
  276. '<h1>{{greeting}}</h1>\n{{>partial}}\n<h3>{{farewell}}</h3>',
  277. {
  278. greeting: function() {
  279. return "Welcome";
  280. },
  281. farewell: function() {
  282. return "Fair enough, right?";
  283. },
  284. partial: {
  285. name: "Chris",
  286. value: 10000,
  287. taxed_value: function() {
  288. return this.value - (this.value * 0.4);
  289. },
  290. in_ca: true
  291. }
  292. },
  293. {partial: 'Hello {{name}}\nYou have just won ${{value}}!\n{{#in_ca}}\nWell, ${{ taxed_value }}, after taxes.\n{{/in_ca}}\n'}
  294. ),
  295. '<h1>Welcome</h1>\nHello Chris\nYou have just won $10000!\n\nWell, $6000, after taxes.\n\n\n<h3>Fair enough, right?</h3>'
  296. );
  297. // matches array_partial.html
  298. equals(
  299. Mustache.to_html(
  300. '{{>partial}}',
  301. {
  302. partial: {
  303. array: ['1', '2', '3', '4']
  304. }
  305. },
  306. { partial: 'Here\'s a non-sense array of values\n{{#array}}\n {{.}}\n{{/array}}' }
  307. ),
  308. 'Here\'s a non-sense array of values\n\n 1\n\n 2\n\n 3\n\n 4\n'
  309. );
  310. // matches template_partial.html
  311. equals(
  312. Mustache.to_html(
  313. '<h1>{{title}}</h1>\n{{>partial}}',
  314. {
  315. title: function() {
  316. return "Welcome";
  317. },
  318. partial: {
  319. again: "Goodbye"
  320. }
  321. },
  322. {partial:'Again, {{again}}!'}
  323. ),
  324. '<h1>Welcome</h1>\nAgain, Goodbye!'
  325. );
  326. // matches partial_recursion.html
  327. equals(
  328. Mustache.to_html(
  329. '{{name}}\n{{#kids}}\n{{>partial}}\n{{/kids}}',
  330. {
  331. name: '1',
  332. kids: [
  333. {
  334. name: '1.1',
  335. children: [
  336. {name: '1.1.1'}
  337. ]
  338. }
  339. ]
  340. },
  341. {partial:'{{name}}\n{{#children}}\n{{>partial}}\n{{/children}}'}
  342. ),
  343. '1\n\n1.1\n\n1.1.1\n\n\n'
  344. );
  345. try {
  346. Mustache.to_html(
  347. '{{>partial}}',
  348. {},
  349. {partal: ''}
  350. );
  351. ok(false);
  352. } catch(e) {
  353. equals(e.message, "Unknown partial 'partial'");
  354. }
  355. });
  356. test("'=' (Set Delimiter)", function() {
  357. expect(1);
  358. // matches delimiter.html
  359. equals(
  360. Mustache.to_html(
  361. '{{=<% %>=}}*\n<% first %>\n* <% second %>\n<%=| |=%>\n* | third |\n|={{ }}=|\n* {{ fourth }}',
  362. {
  363. first: "It worked the first time.",
  364. second: "And it worked the second time.",
  365. third: "Then, surprisingly, it worked the third time.",
  366. fourth: "Fourth time also fine!."
  367. },
  368. {}
  369. ),
  370. '*\nIt worked the first time.\n* And it worked the second time.\n\n* Then, surprisingly, it worked the third time.\n\n* Fourth time also fine!.',
  371. 'Simple Set Delimiter'
  372. );
  373. });
  374. test("'!' (Comments)", function() {
  375. expect(4);
  376. equals(
  377. Mustache.to_html('{{! this is a single line comment !}}'),
  378. '',
  379. 'Single Line Comments');
  380. equals(
  381. Mustache.to_html('{{!this is a multiline comment\ni said this is a multiline comment!}}'),
  382. '',
  383. 'Multiline Comments');
  384. equals(
  385. Mustache.to_html('{{!this {{is}} {{#a}} {{/multiline}} comment\ni {{^said}} ! hello !! bye!}}'),
  386. '',
  387. 'Correct tokenization');
  388. // matches comments.html
  389. equals(
  390. Mustache.to_html(
  391. '<h1>{{title}}{{! just something interesting... or not... !}}</h1>\n',
  392. {
  393. title: function() {
  394. return "A Comedy of Errors";
  395. }
  396. },
  397. {}
  398. ),
  399. '<h1>A Comedy of Errors</h1>\n'
  400. );
  401. });
  402. test("'%' (Pragmas)", function() {
  403. expect(3);
  404. // matches array_of_strings_options.html
  405. equals(
  406. Mustache.to_html(
  407. '{{%IMPLICIT-ITERATOR iterator=rob}}\n{{#array_of_strings_options}}{{rob}} {{/array_of_strings_options}}',
  408. {array_of_strings_options: ['hello', 'world']},
  409. {}
  410. ),
  411. '\nhello world ',
  412. 'IMPLICIT-ITERATOR pragma'
  413. );
  414. // matches unknown_pragma.txt
  415. try {
  416. equals(
  417. Mustache.to_html(
  418. '{{%I-HAVE-THE-GREATEST-MUSTACHE}}\n',
  419. {},
  420. {}
  421. ),
  422. 'hello world ',
  423. 'IMPLICIT-ITERATOR pragma'
  424. );
  425. ok(false);
  426. } catch (e) {
  427. equals(e.message, 'This implementation of mustache doesn\'t understand the \'I-HAVE-THE-GREATEST-MUSTACHE\' pragma');
  428. }
  429. equals(
  430. Mustache.to_html(
  431. '{{%IMPLICIT-ITERATOR}}{{#dataSet}}{{.}}:{{/dataSet}}',
  432. { dataSet: [ 'Object 1', 'Object 2', 'Object 3' ] },
  433. {}
  434. ),
  435. "Object 1:Object 2:Object 3:"
  436. );
  437. });
  438. test("Empty", function() {
  439. expect(2);
  440. // matches empty_template.html
  441. equals(
  442. Mustache.to_html(
  443. '<html><head></head><body><h1>Test</h1></body></html>',
  444. {},
  445. {}
  446. ),
  447. '<html><head></head><body><h1>Test</h1></body></html>',
  448. 'Empty Template'
  449. );
  450. // matches empty_partial.html
  451. equals(
  452. Mustache.to_html(
  453. 'hey {{foo}}\n{{>partial}}\n',
  454. {
  455. foo: 1
  456. },
  457. {partial: 'yo'}
  458. ),
  459. 'hey 1\nyo\n',
  460. 'Empty Partial'
  461. );
  462. });
  463. test("Demo", function() {
  464. expect(2);
  465. // matches simple.html
  466. equals(
  467. Mustache.to_html(
  468. 'Hello {{name}}\nYou have just won ${{value}}!\n{{#in_ca}}\nWell, ${{ taxed_value }}, after taxes.\n{{/in_ca}}',
  469. {
  470. name: "Chris",
  471. value: 10000,
  472. taxed_value: function() {
  473. return this.value - (this.value * 0.4);
  474. },
  475. in_ca: true
  476. },
  477. {}
  478. ),
  479. 'Hello Chris\nYou have just won $10000!\n\nWell, $6000, after taxes.\n',
  480. 'A simple template'
  481. );
  482. // matches complex.html
  483. var template = [
  484. '<h1>{{header}}</h1>',
  485. '{{#list}}',
  486. ' <ul>',
  487. ' {{#item}}',
  488. ' {{#current}}',
  489. ' <li><strong>{{name}}</strong></li>',
  490. ' {{/current}}',
  491. ' {{#link}}',
  492. ' <li><a href="{{url}}">{{name}}</a></li>',
  493. ' {{/link}}',
  494. ' {{/item}}',
  495. ' </ul>',
  496. '{{/list}}',
  497. '{{#empty}}',
  498. ' <p>The list is empty.</p>',
  499. '{{/empty}}'
  500. ].join('\n');
  501. var view = {
  502. header: function() {
  503. return "Colors";
  504. },
  505. item: [
  506. {name: "red", current: true, url: "#Red"},
  507. {name: "green", current: false, url: "#Green"},
  508. {name: "blue", current: false, url: "#Blue"}
  509. ],
  510. link: function() {
  511. return this["current"] !== true;
  512. },
  513. list: function() {
  514. return this.item.length !== 0;
  515. },
  516. empty: function() {
  517. return this.item.length === 0;
  518. }
  519. };
  520. var expected_result = '<h1>Colors</h1>\n\n <ul>\n \n \n <li><strong>red</strong></li>\n \n \n <li><a href=\"#Red\">red</a></li>\n \n \n \n \n <li><a href=\"#Green\">green</a></li>\n \n \n \n \n <li><a href=\"#Blue\">blue</a></li>\n \n \n </ul>\n\n';
  521. equals(
  522. Mustache.to_html(
  523. template,
  524. view,
  525. {}
  526. ),
  527. expected_result,
  528. 'A complex template'
  529. );
  530. });
  531. test("Regression Suite", function() {
  532. expect(4);
  533. // matches bug_11_eating_whitespace.html
  534. equals(
  535. Mustache.to_html(
  536. '{{tag}} foo',
  537. { tag: "yo" },
  538. {}
  539. ),
  540. 'yo foo',
  541. 'Issue 11'
  542. );
  543. // matches delimiters_partial.html
  544. equals(
  545. Mustache.to_html(
  546. '{{#enumerate}}\n{{>partial}}\n{{/enumerate}}',
  547. { enumerate: [ { text: 'A' }, { text: 'B' } ] },
  548. { partial: '{{=[[ ]]=}}\n{{text}}\n[[={{ }}=]]' }
  549. ),
  550. '\n\n{{text}}\n\n\n\n{{text}}\n\n',
  551. 'Issue 44'
  552. );
  553. // matches bug_46_set_delimiter.html
  554. equals(
  555. Mustache.to_html(
  556. '{{=[[ ]]=}}[[#IsMustacheAwesome]]mustache is awesome![[/IsMustacheAwesome]]',
  557. {IsMustacheAwesome: true},
  558. {}
  559. ),
  560. 'mustache is awesome!',
  561. 'Issue 46'
  562. );
  563. // matches Issue #79
  564. equals(
  565. Mustache.to_html(
  566. '{{#inner}}{{f}}{{#inner}}{{b}}{{/inner}}{{/inner}}'
  567. , {
  568. inner: [{
  569. f: 'foo'
  570. , inner: [{
  571. b: 'bar'
  572. }]
  573. }]
  574. }
  575. , {}
  576. )
  577. , 'foobar'
  578. , 'Nested Sections with the same name'
  579. );
  580. });