Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

unit.js 13KB

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