clipboard.test.ts 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import {
  2. createPasteEvent,
  3. parseClipboard,
  4. serializeAsClipboardJSON,
  5. } from "./clipboard";
  6. import { API } from "./tests/helpers/api";
  7. describe("parseClipboard()", () => {
  8. it("should parse JSON as plaintext if not excalidraw-api/clipboard data", async () => {
  9. let text;
  10. let clipboardData;
  11. // -------------------------------------------------------------------------
  12. text = "123";
  13. clipboardData = await parseClipboard(
  14. createPasteEvent({ types: { "text/plain": text } }),
  15. );
  16. expect(clipboardData.text).toBe(text);
  17. // -------------------------------------------------------------------------
  18. text = "[123]";
  19. clipboardData = await parseClipboard(
  20. createPasteEvent({ types: { "text/plain": text } }),
  21. );
  22. expect(clipboardData.text).toBe(text);
  23. // -------------------------------------------------------------------------
  24. text = JSON.stringify({ val: 42 });
  25. clipboardData = await parseClipboard(
  26. createPasteEvent({ types: { "text/plain": text } }),
  27. );
  28. expect(clipboardData.text).toBe(text);
  29. });
  30. it("should parse valid excalidraw JSON if inside text/plain", async () => {
  31. const rect = API.createElement({ type: "rectangle" });
  32. const json = serializeAsClipboardJSON({ elements: [rect], files: null });
  33. const clipboardData = await parseClipboard(
  34. createPasteEvent({
  35. types: {
  36. "text/plain": json,
  37. },
  38. }),
  39. );
  40. expect(clipboardData.elements).toEqual([rect]);
  41. });
  42. it("should parse valid excalidraw JSON if inside text/html", async () => {
  43. const rect = API.createElement({ type: "rectangle" });
  44. let json;
  45. let clipboardData;
  46. // -------------------------------------------------------------------------
  47. json = serializeAsClipboardJSON({ elements: [rect], files: null });
  48. clipboardData = await parseClipboard(
  49. createPasteEvent({
  50. types: {
  51. "text/html": json,
  52. },
  53. }),
  54. );
  55. expect(clipboardData.elements).toEqual([rect]);
  56. // -------------------------------------------------------------------------
  57. json = serializeAsClipboardJSON({ elements: [rect], files: null });
  58. clipboardData = await parseClipboard(
  59. createPasteEvent({
  60. types: {
  61. "text/html": `<div> ${json}</div>`,
  62. },
  63. }),
  64. );
  65. expect(clipboardData.elements).toEqual([rect]);
  66. // -------------------------------------------------------------------------
  67. });
  68. it("should parse <image> `src` urls out of text/html", async () => {
  69. let clipboardData;
  70. // -------------------------------------------------------------------------
  71. clipboardData = await parseClipboard(
  72. createPasteEvent({
  73. types: {
  74. "text/html": `<img src="https://example.com/image.png" />`,
  75. },
  76. }),
  77. );
  78. expect(clipboardData.mixedContent).toEqual([
  79. {
  80. type: "imageUrl",
  81. value: "https://example.com/image.png",
  82. },
  83. ]);
  84. // -------------------------------------------------------------------------
  85. clipboardData = await parseClipboard(
  86. createPasteEvent({
  87. types: {
  88. "text/html": `<div><img src="https://example.com/image.png" /></div><a><img src="https://example.com/image2.png" /></a>`,
  89. },
  90. }),
  91. );
  92. expect(clipboardData.mixedContent).toEqual([
  93. {
  94. type: "imageUrl",
  95. value: "https://example.com/image.png",
  96. },
  97. {
  98. type: "imageUrl",
  99. value: "https://example.com/image2.png",
  100. },
  101. ]);
  102. });
  103. it("should parse text content alongside <image> `src` urls out of text/html", async () => {
  104. const clipboardData = await parseClipboard(
  105. createPasteEvent({
  106. types: {
  107. "text/html": `<a href="https://example.com">hello </a><div><img src="https://example.com/image.png" /></div><b>my friend!</b>`,
  108. },
  109. }),
  110. );
  111. expect(clipboardData.mixedContent).toEqual([
  112. {
  113. type: "text",
  114. // trimmed
  115. value: "hello",
  116. },
  117. {
  118. type: "imageUrl",
  119. value: "https://example.com/image.png",
  120. },
  121. {
  122. type: "text",
  123. value: "my friend!",
  124. },
  125. ]);
  126. });
  127. it("should parse spreadsheet from either text/plain and text/html", async () => {
  128. let clipboardData;
  129. // -------------------------------------------------------------------------
  130. clipboardData = await parseClipboard(
  131. createPasteEvent({
  132. types: {
  133. "text/plain": `a b
  134. 1 2
  135. 4 5
  136. 7 10`,
  137. },
  138. }),
  139. );
  140. expect(clipboardData.spreadsheet).toEqual({
  141. title: "b",
  142. labels: ["1", "4", "7"],
  143. values: [2, 5, 10],
  144. });
  145. // -------------------------------------------------------------------------
  146. clipboardData = await parseClipboard(
  147. createPasteEvent({
  148. types: {
  149. "text/html": `a b
  150. 1 2
  151. 4 5
  152. 7 10`,
  153. },
  154. }),
  155. );
  156. expect(clipboardData.spreadsheet).toEqual({
  157. title: "b",
  158. labels: ["1", "4", "7"],
  159. values: [2, 5, 10],
  160. });
  161. // -------------------------------------------------------------------------
  162. clipboardData = await parseClipboard(
  163. createPasteEvent({
  164. types: {
  165. "text/html": `<html>
  166. <body>
  167. <!--StartFragment--><google-sheets-html-origin><style type="text/css"><!--td {border: 1px solid #cccccc;}br {mso-data-placement:same-cell;}--></style><table xmlns="http://www.w3.org/1999/xhtml" cellspacing="0" cellpadding="0" dir="ltr" border="1" style="table-layout:fixed;font-size:10pt;font-family:Arial;width:0px;border-collapse:collapse;border:none"><colgroup><col width="100"/><col width="100"/></colgroup><tbody><tr style="height:21px;"><td style="overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;a&quot;}">a</td><td style="overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;b&quot;}">b</td></tr><tr style="height:21px;"><td style="overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:2}">2</td></tr><tr style="height:21px;"><td style="overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:4}">4</td><td style="overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:5}">5</td></tr><tr style="height:21px;"><td style="overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:7}">7</td><td style="overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:10}">10</td></tr></tbody></table><!--EndFragment-->
  168. </body>
  169. </html>`,
  170. "text/plain": `a b
  171. 1 2
  172. 4 5
  173. 7 10`,
  174. },
  175. }),
  176. );
  177. expect(clipboardData.spreadsheet).toEqual({
  178. title: "b",
  179. labels: ["1", "4", "7"],
  180. values: [2, 5, 10],
  181. });
  182. });
  183. });