jsx.tsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. import { assert } from "chai";
  2. import { jsx, Fragment, init } from "../../src/index";
  3. describe("snabbdom", function () {
  4. describe("jsx", function () {
  5. it("can be used as a jsxFactory method", function () {
  6. const vnode = <div title="Hello World">Hello World</div>;
  7. assert.deepStrictEqual(vnode, {
  8. sel: "div",
  9. data: { title: "Hello World" },
  10. children: undefined,
  11. elm: undefined,
  12. text: "Hello World",
  13. key: undefined,
  14. });
  15. });
  16. it("creates text property for text only child", function () {
  17. const vnode = <div>foo bar</div>;
  18. assert.deepStrictEqual(vnode, {
  19. sel: "div",
  20. data: {},
  21. children: undefined,
  22. elm: undefined,
  23. text: "foo bar",
  24. key: undefined,
  25. });
  26. });
  27. it("creates an array of children for multiple children", function () {
  28. const vnode = (
  29. <div>
  30. {"foo"}
  31. {"bar"}
  32. </div>
  33. );
  34. assert.deepStrictEqual(vnode, {
  35. sel: "div",
  36. data: {},
  37. children: [
  38. {
  39. sel: undefined,
  40. data: undefined,
  41. children: undefined,
  42. elm: undefined,
  43. text: "foo",
  44. key: undefined,
  45. },
  46. {
  47. sel: undefined,
  48. data: undefined,
  49. children: undefined,
  50. elm: undefined,
  51. text: "bar",
  52. key: undefined,
  53. },
  54. ],
  55. elm: undefined,
  56. text: undefined,
  57. key: undefined,
  58. });
  59. });
  60. it("flattens children", function () {
  61. const vnode = (
  62. <section>
  63. <h1>A Heading</h1>
  64. some description
  65. {["part1", "part2"].map((part) => (
  66. <span>{part}</span>
  67. ))}
  68. </section>
  69. );
  70. assert.deepStrictEqual(vnode, {
  71. sel: "section",
  72. data: {},
  73. children: [
  74. {
  75. sel: "h1",
  76. data: {},
  77. children: undefined,
  78. elm: undefined,
  79. text: "A Heading",
  80. key: undefined,
  81. },
  82. {
  83. sel: undefined,
  84. data: undefined,
  85. children: undefined,
  86. elm: undefined,
  87. text: "some description",
  88. key: undefined,
  89. },
  90. {
  91. sel: "span",
  92. data: {},
  93. children: undefined,
  94. elm: undefined,
  95. text: "part1",
  96. key: undefined,
  97. },
  98. {
  99. sel: "span",
  100. data: {},
  101. children: undefined,
  102. elm: undefined,
  103. text: "part2",
  104. key: undefined,
  105. },
  106. ],
  107. elm: undefined,
  108. text: undefined,
  109. key: undefined,
  110. });
  111. });
  112. it("removes falsey children", function () {
  113. const showLogin = false;
  114. const showCaptcha = false;
  115. const loginAttempts = 0;
  116. const userName = "";
  117. const profilePic = undefined;
  118. const isLoggedIn = true;
  119. const vnode = (
  120. <div>
  121. Login Form
  122. {showLogin && <login-form />}
  123. {showCaptcha ? <captcha-form /> : null}
  124. {userName}
  125. {profilePic}
  126. Login Attempts: {loginAttempts}
  127. Logged In: {isLoggedIn}
  128. </div>
  129. );
  130. assert.deepStrictEqual(vnode, {
  131. sel: "div",
  132. data: {},
  133. children: [
  134. {
  135. sel: undefined,
  136. data: undefined,
  137. children: undefined,
  138. elm: undefined,
  139. text: "Login Form",
  140. key: undefined,
  141. },
  142. {
  143. sel: undefined,
  144. data: undefined,
  145. children: undefined,
  146. elm: undefined,
  147. text: "Login Attempts: ",
  148. key: undefined,
  149. },
  150. {
  151. sel: undefined,
  152. data: undefined,
  153. children: undefined,
  154. elm: undefined,
  155. text: "0",
  156. key: undefined,
  157. },
  158. {
  159. sel: undefined,
  160. data: undefined,
  161. children: undefined,
  162. elm: undefined,
  163. text: "Logged In: ",
  164. key: undefined,
  165. },
  166. {
  167. sel: undefined,
  168. data: undefined,
  169. children: undefined,
  170. elm: undefined,
  171. text: "true",
  172. key: undefined,
  173. },
  174. ],
  175. elm: undefined,
  176. text: undefined,
  177. key: undefined,
  178. });
  179. });
  180. it("works with a function component", function () {
  181. // workaround linter issue
  182. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  183. const Part = ({ part }: { part: string }) => <span>{part}</span>;
  184. const vnode = (
  185. <div>
  186. <a attrs={{ href: "https://github.com/snabbdom/snabbdom" }}>
  187. Snabbdom
  188. </a>
  189. and tsx
  190. {["work", "like", "a", "charm!"].map((part) => (
  191. <Part part={part}></Part>
  192. ))}
  193. {"💃🕺🎉"}
  194. </div>
  195. );
  196. assert.deepStrictEqual(vnode, {
  197. sel: "div",
  198. data: {},
  199. children: [
  200. {
  201. sel: "a",
  202. data: { attrs: { href: "https://github.com/snabbdom/snabbdom" } },
  203. children: undefined,
  204. elm: undefined,
  205. text: "Snabbdom",
  206. key: undefined,
  207. },
  208. {
  209. sel: undefined,
  210. data: undefined,
  211. children: undefined,
  212. elm: undefined,
  213. text: "and tsx",
  214. key: undefined,
  215. },
  216. {
  217. sel: "span",
  218. data: {},
  219. children: undefined,
  220. elm: undefined,
  221. text: "work",
  222. key: undefined,
  223. },
  224. {
  225. sel: "span",
  226. data: {},
  227. children: undefined,
  228. elm: undefined,
  229. text: "like",
  230. key: undefined,
  231. },
  232. {
  233. sel: "span",
  234. data: {},
  235. children: undefined,
  236. elm: undefined,
  237. text: "a",
  238. key: undefined,
  239. },
  240. {
  241. sel: "span",
  242. data: {},
  243. children: undefined,
  244. elm: undefined,
  245. text: "charm!",
  246. key: undefined,
  247. },
  248. {
  249. sel: undefined,
  250. data: undefined,
  251. children: undefined,
  252. elm: undefined,
  253. text: "💃🕺🎉",
  254. key: undefined,
  255. },
  256. ],
  257. elm: undefined,
  258. text: undefined,
  259. key: undefined,
  260. });
  261. });
  262. });
  263. describe("Fragment", function () {
  264. it("can be used as a jsxFragmentFactory method", function () {
  265. const vnode = <>Hello World</>;
  266. assert.deepStrictEqual(vnode, {
  267. sel: undefined,
  268. data: undefined,
  269. children: undefined,
  270. elm: undefined,
  271. text: "Hello World",
  272. key: undefined,
  273. });
  274. });
  275. it("creates text property for text only child", function () {
  276. const vnode = <>foo bar</>;
  277. assert.deepStrictEqual(vnode, {
  278. sel: undefined,
  279. data: undefined,
  280. children: undefined,
  281. elm: undefined,
  282. text: "foo bar",
  283. key: undefined,
  284. });
  285. });
  286. it("creates an array of children for multiple children", function () {
  287. const vnode = (
  288. <>
  289. {"foo"}
  290. {"bar"}
  291. </>
  292. );
  293. assert.deepStrictEqual(vnode, {
  294. sel: undefined,
  295. data: {},
  296. children: [
  297. {
  298. sel: undefined,
  299. data: undefined,
  300. children: undefined,
  301. elm: undefined,
  302. text: "foo",
  303. key: undefined,
  304. },
  305. {
  306. sel: undefined,
  307. data: undefined,
  308. children: undefined,
  309. elm: undefined,
  310. text: "bar",
  311. key: undefined,
  312. },
  313. ],
  314. elm: undefined,
  315. text: undefined,
  316. key: undefined,
  317. });
  318. });
  319. it("flattens children", function () {
  320. const vnode = (
  321. <>
  322. <h1>A Heading</h1>
  323. some description
  324. {["part1", "part2"].map((part) => (
  325. <span>{part}</span>
  326. ))}
  327. </>
  328. );
  329. assert.deepStrictEqual(vnode, {
  330. sel: undefined,
  331. data: {},
  332. children: [
  333. {
  334. sel: "h1",
  335. data: {},
  336. children: undefined,
  337. elm: undefined,
  338. text: "A Heading",
  339. key: undefined,
  340. },
  341. {
  342. sel: undefined,
  343. data: undefined,
  344. children: undefined,
  345. elm: undefined,
  346. text: "some description",
  347. key: undefined,
  348. },
  349. {
  350. sel: "span",
  351. data: {},
  352. children: undefined,
  353. elm: undefined,
  354. text: "part1",
  355. key: undefined,
  356. },
  357. {
  358. sel: "span",
  359. data: {},
  360. children: undefined,
  361. elm: undefined,
  362. text: "part2",
  363. key: undefined,
  364. },
  365. ],
  366. elm: undefined,
  367. text: undefined,
  368. key: undefined,
  369. });
  370. });
  371. it("removes falsey children", function () {
  372. const showLogin = false;
  373. const showCaptcha = false;
  374. const loginAttempts = 0;
  375. const userName = "";
  376. const profilePic = undefined;
  377. const isLoggedIn = true;
  378. const vnode = (
  379. <>
  380. Login Form
  381. {showLogin && <login-form />}
  382. {showCaptcha ? <captcha-form /> : null}
  383. {userName}
  384. {profilePic}
  385. Login Attempts: {loginAttempts}
  386. Logged In: {isLoggedIn}
  387. </>
  388. );
  389. assert.deepStrictEqual(vnode, {
  390. sel: undefined,
  391. data: {},
  392. children: [
  393. {
  394. sel: undefined,
  395. data: undefined,
  396. children: undefined,
  397. elm: undefined,
  398. text: "Login Form",
  399. key: undefined,
  400. },
  401. {
  402. sel: undefined,
  403. data: undefined,
  404. children: undefined,
  405. elm: undefined,
  406. text: "Login Attempts: ",
  407. key: undefined,
  408. },
  409. {
  410. sel: undefined,
  411. data: undefined,
  412. children: undefined,
  413. elm: undefined,
  414. text: "0",
  415. key: undefined,
  416. },
  417. {
  418. sel: undefined,
  419. data: undefined,
  420. children: undefined,
  421. elm: undefined,
  422. text: "Logged In: ",
  423. key: undefined,
  424. },
  425. {
  426. sel: undefined,
  427. data: undefined,
  428. children: undefined,
  429. elm: undefined,
  430. text: "true",
  431. key: undefined,
  432. },
  433. ],
  434. elm: undefined,
  435. text: undefined,
  436. key: undefined,
  437. });
  438. });
  439. it("works with a function component", function () {
  440. // workaround linter issue
  441. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  442. const Part = ({ part }: { part: string }) => <>{part}</>;
  443. const vnode = (
  444. <div>
  445. <a attrs={{ href: "https://github.com/snabbdom/snabbdom" }}>
  446. Snabbdom
  447. </a>
  448. and tsx
  449. {["work", "like", "a", "charm!"].map((part) => (
  450. <Part part={part}></Part>
  451. ))}
  452. {"💃🕺🎉"}
  453. </div>
  454. );
  455. assert.deepStrictEqual(vnode, {
  456. sel: "div",
  457. data: {},
  458. children: [
  459. {
  460. sel: "a",
  461. data: { attrs: { href: "https://github.com/snabbdom/snabbdom" } },
  462. children: undefined,
  463. elm: undefined,
  464. text: "Snabbdom",
  465. key: undefined,
  466. },
  467. {
  468. sel: undefined,
  469. data: undefined,
  470. children: undefined,
  471. elm: undefined,
  472. text: "and tsx",
  473. key: undefined,
  474. },
  475. {
  476. sel: undefined,
  477. data: undefined,
  478. children: undefined,
  479. elm: undefined,
  480. text: "work",
  481. key: undefined,
  482. },
  483. {
  484. sel: undefined,
  485. data: undefined,
  486. children: undefined,
  487. elm: undefined,
  488. text: "like",
  489. key: undefined,
  490. },
  491. {
  492. sel: undefined,
  493. data: undefined,
  494. children: undefined,
  495. elm: undefined,
  496. text: "a",
  497. key: undefined,
  498. },
  499. {
  500. sel: undefined,
  501. data: undefined,
  502. children: undefined,
  503. elm: undefined,
  504. text: "charm!",
  505. key: undefined,
  506. },
  507. {
  508. sel: undefined,
  509. data: undefined,
  510. children: undefined,
  511. elm: undefined,
  512. text: "💃🕺🎉",
  513. key: undefined,
  514. },
  515. ],
  516. elm: undefined,
  517. text: undefined,
  518. key: undefined,
  519. });
  520. });
  521. it("can correctly be patched", function () {
  522. const patch = init([], undefined, {
  523. experimental: {
  524. fragments: true,
  525. },
  526. });
  527. const container = document.createElement("div");
  528. const vnode0 = (
  529. <>
  530. <span>Nested </span>
  531. <>
  532. children
  533. <> will be flattened</>
  534. </>
  535. </>
  536. );
  537. patch(container, vnode0);
  538. assert.strictEqual(vnode0.elm?.nodeType, document.DOCUMENT_FRAGMENT_NODE);
  539. assert.strictEqual(
  540. vnode0.elm?.textContent,
  541. "Nested children will be flattened"
  542. );
  543. const vnode1 = (
  544. <div>
  545. <span>Nested </span>
  546. <>
  547. child nodes
  548. {[" will", " be", " patched"]}
  549. </>
  550. </div>
  551. );
  552. patch(vnode0, vnode1);
  553. assert.strictEqual((vnode1.elm as HTMLElement).tagName, "DIV");
  554. assert.strictEqual(
  555. vnode1.elm?.textContent,
  556. "Nested child nodes will be patched"
  557. );
  558. const vnode2 = (
  559. <Fragment key="foo">
  560. And <>fragment again!</>
  561. </Fragment>
  562. );
  563. patch(vnode1, vnode2);
  564. assert.strictEqual(vnode2.elm?.nodeType, document.DOCUMENT_FRAGMENT_NODE);
  565. assert.strictEqual(vnode2.elm?.textContent, "And fragment again!");
  566. });
  567. });
  568. });