Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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