compile.test.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. import {
  2. AUTO_BODY,
  3. COMPILE_ERROR,
  4. FORM_DATA,
  5. ID,
  6. INDICATORS,
  7. MEMO,
  8. MODE,
  9. ALLOWED_CONTENT_TYPES,
  10. PARSE_ERROR,
  11. RENDER_ERROR,
  12. REQUEST_OBJECT_ERROR,
  13. COMPILE_OPTIONS_ERROR,
  14. SOURCE,
  15. AFTER,
  16. DISALLOWED_TAGS,
  17. SANITIZE
  18. } from "../config/config";
  19. import { checkFunction } from "../shared/utils";
  20. import { compile } from "../../src/main";
  21. import { e, eq, createTestObj1, createTestObj2 } from "./functions";
  22. /**
  23. * Function "compile"
  24. */
  25. describe("compile function", () => {
  26. e(
  27. "throws an error if the TEMPLATE is not a stringthrows an error if the TEMPLATE is not a string",
  28. () => compile(123 as any),
  29. `${COMPILE_ERROR}: Template was not found or the type of the passed value is not string`
  30. );
  31. e(
  32. "throws an error if the TEMPLATE is an empty string",
  33. () => compile(""),
  34. `${COMPILE_ERROR}: Template must not be a falsey value`
  35. );
  36. e(
  37. "only accepts COMPILES OPTIONS as an object",
  38. () => compile("some template", "some text" as any),
  39. `${COMPILE_OPTIONS_ERROR}: Options must be an object`
  40. );
  41. e(
  42. `only accepts the '${MEMO}' property in the COMPILE OPTIONS as a boolean`,
  43. () => compile("some template", { memo: 123 as unknown as boolean }),
  44. `${COMPILE_OPTIONS_ERROR}: The value of the property ${MEMO} must be a boolean`
  45. );
  46. e(
  47. "throws an error if the TEMPLATE string doesn't contain a request object",
  48. () => compile("<div></div>"),
  49. `${PARSE_ERROR}: Request object not found`
  50. );
  51. e(
  52. "",
  53. () => compile(`<div>{{src:"123"}}<!--hmpl1--></div>`),
  54. `${PARSE_ERROR}: Request object with id "1" not found`
  55. );
  56. e(
  57. `throws an error if the REQUEST OBJECT doesn't contain the '${SOURCE}' property`,
  58. () => compile(createTestObj2(`{{ "repeat":true }}`)),
  59. `${REQUEST_OBJECT_ERROR}: The "${SOURCE}" property are not found or empty`
  60. );
  61. e(
  62. "throws an error if the REQUEST OBJECT contains invalid properties",
  63. () => compile(createTestObj1({ a: "" })),
  64. `${REQUEST_OBJECT_ERROR}: Property "a" is not processed`
  65. );
  66. e(
  67. `only accepts the '${INDICATORS}' property in the REQUEST OBJECT as an array`,
  68. () => compile(createTestObj1({ [INDICATORS]: "" })),
  69. `${REQUEST_OBJECT_ERROR}: The value of the property "${INDICATORS}" must be an array`
  70. );
  71. e(
  72. `only accepts the '${ID}' property in the REQUEST OBJECT as a string`,
  73. () => compile(createTestObj1({ [ID]: [] })),
  74. `${REQUEST_OBJECT_ERROR}: The value of the property "${ID}" must be a string`
  75. );
  76. e(
  77. `only accepts the '${MEMO}' property in the REQUEST OBJECT as a boolean`,
  78. () => compile(createTestObj1({ [MEMO]: [] })),
  79. `${REQUEST_OBJECT_ERROR}: The value of the property "${MEMO}" must be a boolean value`
  80. );
  81. e(
  82. `only accepts the '${MODE}' property in the REQUEST OBJECT as a boolean`,
  83. () => compile(createTestObj1({ [MODE]: [] })),
  84. `${REQUEST_OBJECT_ERROR}: The value of the property "${MODE}" must be a boolean value`
  85. );
  86. e(
  87. `only accepts the '${AUTO_BODY}' property in the REQUEST OBJECT as a boolean or an object`,
  88. () => compile(createTestObj1({ [AUTO_BODY]: [] })),
  89. `${REQUEST_OBJECT_ERROR}: Expected a boolean or object, but got neither`
  90. );
  91. e(
  92. `throws an error if the '${AUTO_BODY}' property in the REQUEST OBJECT contains invalid properties`,
  93. () => compile(createTestObj1({ [AUTO_BODY]: { a: "" } })),
  94. `${REQUEST_OBJECT_ERROR}: Unexpected property "a"`
  95. );
  96. e(
  97. `only accepts the '${AUTO_BODY}.${FORM_DATA}' property in the REQUEST OBJECT as a boolean`,
  98. () => compile(createTestObj1({ [AUTO_BODY]: { [FORM_DATA]: "" } })),
  99. `${REQUEST_OBJECT_ERROR}: The "${FORM_DATA}" property should be a boolean`
  100. );
  101. e(
  102. `only accepts the '${ALLOWED_CONTENT_TYPES}' property in the REQUEST OBJECT as a "*" or an array of strings`,
  103. () => compile(createTestObj1({ [ALLOWED_CONTENT_TYPES]: {} })),
  104. `${REQUEST_OBJECT_ERROR}: Expected "*" or string array, but got neither`
  105. );
  106. e(
  107. `throws an error if the '${ALLOWED_CONTENT_TYPES}' property in the REQUEST OBJECT contains non-string element at index 0 of the array`,
  108. () => compile(createTestObj1({ [ALLOWED_CONTENT_TYPES]: [1] })),
  109. `${REQUEST_OBJECT_ERROR}: In the array, the element with index 0 is not a string`
  110. );
  111. e(
  112. "only accepts the 'allowedContentTypes' property in the COMPILE OPTIONS as a '*' or an array of strings",
  113. () =>
  114. compile(createTestObj2(`{{ "src":"/api/test" }}`), {
  115. allowedContentTypes: {} as any
  116. }),
  117. `${COMPILE_OPTIONS_ERROR}: Expected "*" or string array, but got neither`
  118. );
  119. e(
  120. "throws an error if the 'allowedContentTypes' property in the COMPILE OPTIONS contains non-string element at index 0 of the array",
  121. () =>
  122. compile(createTestObj2(`{{ "src":"/api/test" }}`), {
  123. allowedContentTypes: [1] as any
  124. }),
  125. `${COMPILE_OPTIONS_ERROR}: In the array, the element with index 0 is not a string`
  126. );
  127. e(
  128. ``,
  129. () =>
  130. compile(createTestObj2(`{{ "src":"/api/test" }}`), {
  131. disallowedTags: true as any
  132. }),
  133. `${COMPILE_OPTIONS_ERROR}: The value of the property "${DISALLOWED_TAGS}" must be an array`
  134. );
  135. e(
  136. ``,
  137. () =>
  138. compile(createTestObj2(`{{ "src":"/api/test" }}`), {
  139. disallowedTags: ["div" as any]
  140. }),
  141. `${COMPILE_OPTIONS_ERROR}: The value "div" is not processed`
  142. );
  143. e(
  144. ``,
  145. () =>
  146. compile(createTestObj2(`{{ "src":"/api/test" }}`), {
  147. sanitize: ["div"] as any
  148. }),
  149. `${COMPILE_OPTIONS_ERROR}: The value of the property "${SANITIZE}" must be a boolean`
  150. );
  151. e(
  152. `throws an error if the '${SOURCE}' property in the REQUEST OBJECT is an array instead of a string`,
  153. () => compile(createTestObj1({ [SOURCE]: [] })),
  154. `${REQUEST_OBJECT_ERROR}: The value of the property "${SOURCE}" must be a string`
  155. );
  156. e(
  157. "",
  158. () => compile(createTestObj1({ [SOURCE]: [] })),
  159. `${REQUEST_OBJECT_ERROR}: The value of the property "${SOURCE}" must be a string`
  160. );
  161. e(
  162. "throws an error if the REQUEST OBJECT doesn't has proper spacing between the curly brackets",
  163. () => compile(createTestObj2(`{{ "src":"/api/test" }e}}`)),
  164. `${PARSE_ERROR}: There is no empty space between the curly brackets`
  165. );
  166. e(
  167. "",
  168. () =>
  169. compile(
  170. createTestObj2(`{{ "src":"/api/test", "indicators":{"property":{}}}`)
  171. ),
  172. `${PARSE_ERROR}: There is no empty space between the curly brackets`
  173. );
  174. e(
  175. "throws an error if the REQUEST OBJECT contains invalid property",
  176. () =>
  177. compile(
  178. createTestObj2(`<div>
  179. <form onsubmit="function prevent(e){e.preventDefault();};return prevent(event);" id="form">
  180. <div class="form-example">
  181. <label for="login">Login: </label>
  182. <input type="login" name="login" id="login" required />
  183. </div>
  184. <div class="form-example">
  185. <input type="submit" value="Register!" />
  186. </div>
  187. </form>
  188. <p>
  189. {{src:"", c:{a:{d:{}}}, indicators:[{ a:{}, b:{} }] }}
  190. </p>
  191. </div>`)
  192. ),
  193. `${REQUEST_OBJECT_ERROR}: Property "c" is not processed`
  194. );
  195. e(
  196. `throws an error if the REQUEST OBJECT doesn't have the ${SOURCE} property is an empty string`,
  197. () =>
  198. compile(
  199. createTestObj2(`<div>
  200. <form onsubmit="function prevent(e){e.preventDefault();};return prevent(event);" id="form">
  201. <div class="form-example">
  202. <label for="login">Login: </label>
  203. <input type="login" name="login" id="login" required />
  204. </div>
  205. <div class="form-example">
  206. <input type="submit" value="Register!" />
  207. </div>
  208. </form>
  209. <p>
  210. {{src:"", indicators:{a:{d:{}}}, indicators:[{ a:{}, b:{} }] }}
  211. </p>
  212. </div>`)
  213. ),
  214. `${REQUEST_OBJECT_ERROR}: The "${SOURCE}" property are not found or empty`
  215. );
  216. e(
  217. "throws an error if the REQUEST OBJECT doesn't have proper spacing between the curly brackets",
  218. () =>
  219. compile(
  220. createTestObj2(`<div>
  221. <form onsubmit="function prevent(e){e.preventDefault();};return prevent(event);" id="form">
  222. <div class="form-example">
  223. <label for="login">Login: </label>
  224. <input type="login" name="login" id="login" required />
  225. </div>
  226. <div class="form-example">
  227. <input type="submit" value="Register!" />
  228. </div>
  229. </form>
  230. <p>
  231. { {src:"", c:{a:{d:{}}}, indicators:[{ a:{}, b:{} }] } test }
  232. </p>
  233. </div>`)
  234. ),
  235. `${PARSE_ERROR}: There is no empty space between the curly brackets`
  236. );
  237. e(
  238. "throw an error if the TEMPLATE includes more than one top-level node",
  239. () => compile(`${createTestObj2(`{{ "src":"/api/test" }}`)}<div></div>`),
  240. `${RENDER_ERROR}: Template includes only one node of the Element type or one response object`
  241. );
  242. e(
  243. `throws an error if the '${AUTO_BODY}' property in the REQUEST OBJECT is true without the '${AFTER}' property`,
  244. () => compile(createTestObj2(`{{ "src":"/api/test", "autoBody": true }}`)),
  245. `${REQUEST_OBJECT_ERROR}: The "${AUTO_BODY}" property does not work without the "${AFTER}" property`
  246. );
  247. e(
  248. `throws an error if the event target is not provided for '${AFTER}' property in the REQUEST OBJECT`,
  249. () =>
  250. compile(
  251. createTestObj2(
  252. `<form id="form"></form>{{ "src":"/api/test", "after":"submit" }}`
  253. )
  254. ),
  255. `${REQUEST_OBJECT_ERROR}: The "${AFTER}" property doesn't work without EventTargets`
  256. );
  257. e(
  258. `throws an error if the '${MODE}' property in the REQUEST OBJECT is true without the '${AFTER}' property`,
  259. () =>
  260. compile(
  261. createTestObj2(
  262. `<form id="form"></form>{{ "src":"/api/test", "repeat":true }}`
  263. )
  264. ),
  265. `${REQUEST_OBJECT_ERROR}: The "${MODE}" property doesn't work without "${AFTER}" property`
  266. );
  267. e(
  268. ``,
  269. () =>
  270. compile(createTestObj2(`{{ "src":"/api/test", "disallowedTags":true }}`)),
  271. `${REQUEST_OBJECT_ERROR}: The value of the property "${DISALLOWED_TAGS}" must be an array`
  272. );
  273. e(
  274. ``,
  275. () =>
  276. compile(
  277. createTestObj2(`{{ "src":"/api/test", disallowedTags: ["div"] }}`)
  278. ),
  279. `${REQUEST_OBJECT_ERROR}: The value "div" is not processed`
  280. );
  281. e(
  282. ``,
  283. () => compile(createTestObj2(`{{ "src":"/api/test", sanitize: ["div"] }}`)),
  284. `${REQUEST_OBJECT_ERROR}: The value of the property "${SANITIZE}" must be a boolean`
  285. );
  286. eq(
  287. `returns a template function when provided a TEMPLATE with just ${SOURCE} property`,
  288. checkFunction(compile(createTestObj2(`{{ "src":"/api/test" }}`))),
  289. true
  290. );
  291. eq(
  292. "",
  293. compile(
  294. createTestObj2(
  295. `<form id="form"></form>{{ "src":"/api/test", "after":"submit:#form", "autoBody": false }}`
  296. ),
  297. {
  298. autoBody: true
  299. }
  300. )().response?.outerHTML,
  301. '<div><form id="form"></form><!--hmpl0--></div>'
  302. );
  303. eq(
  304. "",
  305. compile(
  306. createTestObj2(
  307. `<form id="form"></form>{{ "src":"/api/test", "after":"submit:#form", "autoBody": true }}`
  308. ),
  309. {
  310. autoBody: false
  311. }
  312. )().response?.outerHTML,
  313. '<div><form id="form"></form><!--hmpl0--></div>'
  314. );
  315. eq(
  316. "",
  317. compile(
  318. createTestObj2(
  319. `<form id="form"></form>{{ "src":"/api/test", "after":"submit:#form" }}`
  320. ),
  321. {
  322. autoBody: false
  323. }
  324. )().response?.outerHTML,
  325. '<div><form id="form"></form><!--hmpl0--></div>'
  326. );
  327. eq(
  328. "",
  329. compile(
  330. createTestObj2(
  331. `<form id="form"></form>{{ "src":"/api/test", "after":"submit:#form" }}`
  332. ),
  333. {
  334. autoBody: true
  335. }
  336. )().response?.outerHTML,
  337. '<div><form id="form"></form><!--hmpl0--></div>'
  338. );
  339. eq(
  340. "",
  341. compile(
  342. createTestObj2(
  343. `<form id="form"></form>{{ "src":"/api/test", "after":"submit:#form" }}`
  344. ),
  345. {
  346. autoBody: {
  347. formData: false
  348. }
  349. }
  350. )().response?.outerHTML,
  351. '<div><form id="form"></form><!--hmpl0--></div>'
  352. );
  353. eq(
  354. "",
  355. compile(
  356. createTestObj2(
  357. `<form id="form"></form>{{ "src":"/api/test", "after":"submit:#form" }}`
  358. ),
  359. {
  360. autoBody: {
  361. formData: true
  362. }
  363. }
  364. )().response?.outerHTML,
  365. '<div><form id="form"></form><!--hmpl0--></div>'
  366. );
  367. eq(
  368. "",
  369. compile(
  370. createTestObj2(
  371. `<form id="form"></form>{{ "src":"/api/test", "after":"submit:#form", "autoBody": { "formData": true } }}`
  372. ),
  373. {
  374. autoBody: false
  375. }
  376. )().response?.outerHTML,
  377. '<div><form id="form"></form><!--hmpl0--></div>'
  378. );
  379. eq(
  380. "",
  381. compile(
  382. createTestObj2(
  383. `<form id="form"></form>{{ "src":"/api/test", "after":"submit:#form", "autoBody": { "formData": true } }}`
  384. ),
  385. {
  386. autoBody: true
  387. }
  388. )().response?.outerHTML,
  389. '<div><form id="form"></form><!--hmpl0--></div>'
  390. );
  391. eq(
  392. "",
  393. compile(
  394. createTestObj2(
  395. `<form id="form"></form>{{ "src":"/api/test", "after":"submit:#form", "autoBody": { "formData": true } }}`
  396. )
  397. )().response?.outerHTML,
  398. '<div><form id="form"></form><!--hmpl0--></div>'
  399. );
  400. eq(
  401. "",
  402. compile(
  403. createTestObj2(
  404. `<form id="form"></form>{{ "src":"/api/test", "after":"submit:#form", "autoBody": { "formData": false } }}`
  405. )
  406. )().response?.outerHTML,
  407. '<div><form id="form"></form><!--hmpl0--></div>'
  408. );
  409. eq(
  410. "",
  411. compile(
  412. createTestObj2(
  413. `<form id="form"></form>{{ "src":"/api/test", "after":"submit:#form", "autoBody": { "formData": false } }}`
  414. )
  415. )(() => ({})).response?.outerHTML,
  416. '<div><form id="form"></form><!--hmpl0--></div>'
  417. );
  418. eq(
  419. "",
  420. compile(
  421. createTestObj2(
  422. `<form id="form"></form>{{ "src":"/api/test", "after":"submit:#form", "autoBody": { "formData": false }, "initId":"1" }}`
  423. )
  424. )([
  425. {
  426. id: "1",
  427. value: {}
  428. }
  429. ]).response?.outerHTML,
  430. '<div><form id="form"></form><!--hmpl0--></div>'
  431. );
  432. eq(
  433. "",
  434. compile(
  435. createTestObj2(
  436. `<form id="form"></form>{{ "src":"/api/test", "after":"submit:#form", "initId":"1" }} {{ "src":"/api/test", "after":"submit:#form", "initId":"2" }}`
  437. )
  438. )([
  439. {
  440. id: "1",
  441. value: {}
  442. },
  443. {
  444. id: "2",
  445. value: {}
  446. }
  447. ]).response?.outerHTML,
  448. '<div><form id="form"></form><!--hmpl0--><!--hmpl1--></div>'
  449. );
  450. });