Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

623 lines
13KB

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