tooltip.test.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. import { sanitizeHtml, tooltipHtml } from '@superset-ui/core';
  20. const TITLE_STYLE =
  21. 'style="font-weight: 700;max-width:300px;overflow:hidden;text-overflow:ellipsis;"';
  22. const TR_STYLE = 'style="opacity:0.8;"';
  23. const TR_FOCUS_STYLE = 'style="font-weight:700;"';
  24. const TD_TEXT_STYLE =
  25. 'style="text-align:left;padding-left:0px;max-width:300px;overflow:hidden;text-overflow:ellipsis;"';
  26. const TD_NUMBER_STYLE =
  27. 'style="text-align:right;padding-left:16px;max-width:300px;overflow:hidden;text-overflow:ellipsis;"';
  28. const data = [
  29. ['a', 'b', 'c'],
  30. ['1', '2', '3'],
  31. ];
  32. function removeWhitespaces(text: string) {
  33. return text.replace(/\s/g, '');
  34. }
  35. test('should return a table with the given data', () => {
  36. const title = 'Title';
  37. const html = removeWhitespaces(tooltipHtml(data, title));
  38. const expectedHtml = removeWhitespaces(
  39. sanitizeHtml(`
  40. <div>
  41. <span ${TITLE_STYLE}>Title</span>
  42. <table>
  43. <tr ${TR_STYLE}>
  44. <td ${TD_TEXT_STYLE}>a</td>
  45. <td ${TD_NUMBER_STYLE}>b</td>
  46. <td ${TD_NUMBER_STYLE}>c</td>
  47. </tr>
  48. <tr ${TR_STYLE}>
  49. <td ${TD_TEXT_STYLE}>1</td>
  50. <td ${TD_NUMBER_STYLE}>2</td>
  51. <td ${TD_NUMBER_STYLE}>3</td>
  52. </tr>
  53. </table>
  54. </div>`),
  55. );
  56. expect(html).toMatch(expectedHtml);
  57. });
  58. test('should return a table with the given data and a focused row', () => {
  59. const title = 'Title';
  60. const focusedRow = 1;
  61. const html = removeWhitespaces(tooltipHtml(data, title, focusedRow));
  62. const expectedHtml = removeWhitespaces(
  63. sanitizeHtml(`
  64. <div>
  65. <span ${TITLE_STYLE}>Title</span>
  66. <table>
  67. <tr ${TR_STYLE}>
  68. <td ${TD_TEXT_STYLE}>a</td>
  69. <td ${TD_NUMBER_STYLE}>b</td>
  70. <td ${TD_NUMBER_STYLE}>c</td>
  71. </tr>
  72. <tr ${TR_FOCUS_STYLE}>
  73. <td ${TD_TEXT_STYLE}>1</td>
  74. <td ${TD_NUMBER_STYLE}>2</td>
  75. <td ${TD_NUMBER_STYLE}>3</td>
  76. </tr>
  77. </table>
  78. </div>`),
  79. );
  80. expect(html).toMatch(expectedHtml);
  81. });
  82. test('should return a table with no data', () => {
  83. const title = 'Title';
  84. const html = removeWhitespaces(tooltipHtml([], title));
  85. const expectedHtml = removeWhitespaces(
  86. sanitizeHtml(`
  87. <div>
  88. <span ${TITLE_STYLE}>Title</span>
  89. <table>
  90. <tr><td>No data</td></tr>
  91. </table>
  92. </div>`),
  93. );
  94. expect(html).toMatch(expectedHtml);
  95. });
  96. test('should return a table with the given data and no title', () => {
  97. const html = removeWhitespaces(tooltipHtml(data));
  98. const expectedHtml = removeWhitespaces(
  99. sanitizeHtml(`
  100. <div>
  101. <table>
  102. <tr ${TR_STYLE}>
  103. <td ${TD_TEXT_STYLE}>a</td>
  104. <td ${TD_NUMBER_STYLE}>b</td>
  105. <td ${TD_NUMBER_STYLE}>c</td>
  106. </tr>
  107. <tr ${TR_STYLE}>
  108. <td ${TD_TEXT_STYLE}>1</td>
  109. <td ${TD_NUMBER_STYLE}>2</td>
  110. <td ${TD_NUMBER_STYLE}>3</td>
  111. </tr>
  112. </table>
  113. </div>`),
  114. );
  115. expect(html).toMatch(expectedHtml);
  116. });
  117. test('should sanitize HTML input', () => {
  118. const title = 'Title<script>alert("message");</script>';
  119. const data = [
  120. ['<b onclick="alert(\'message\')">B message</b>', 'message2'],
  121. ['<img src="x" onerror="alert(\'message\');" />', '<i>Italic</i>'],
  122. ];
  123. const html = removeWhitespaces(tooltipHtml(data, title));
  124. const expectedHtml = removeWhitespaces(
  125. sanitizeHtml(`
  126. <div>
  127. <span ${TITLE_STYLE}>Titlealert("message");</span>
  128. <table>
  129. <tr ${TR_STYLE}>
  130. <td ${TD_TEXT_STYLE}><b>B message</b></td>
  131. <td ${TD_NUMBER_STYLE}>message2</td>
  132. </tr>
  133. <tr ${TR_STYLE}>
  134. <td ${TD_TEXT_STYLE}><img src="x" /></td>
  135. <td ${TD_NUMBER_STYLE}><i>Italic</i></td>
  136. </tr>
  137. </table>
  138. </div>`),
  139. );
  140. expect(html).toMatch(expectedHtml);
  141. });
  142. test('should preserve table styling after sanitization (fixes ECharts tooltip formatting)', () => {
  143. const tableWithStyles = `
  144. <table>
  145. <tr style="opacity: 0.8;">
  146. <td style="text-align: left; padding-left: 0px;">Label</td>
  147. <td style="text-align: right; padding-left: 16px;">Value</td>
  148. </tr>
  149. </table>
  150. `;
  151. const sanitized = sanitizeHtml(tableWithStyles);
  152. expect(sanitized).toContain('style="opacity: 0.8;"');
  153. expect(sanitized).toContain('style="text-align: left; padding-left: 0px;"');
  154. expect(sanitized).toContain('style="text-align: right; padding-left: 16px;"');
  155. const data = [
  156. ['Metric', 'Value'],
  157. ['Sales', '$1,234'],
  158. ];
  159. const html = tooltipHtml(data, 'Test Tooltip');
  160. expect(html).toContain('style="opacity: 0.8;"');
  161. expect(html).toContain('text-align: left');
  162. expect(html).toContain('text-align: right');
  163. expect(html).toContain('padding-left: 0px');
  164. expect(html).toContain('padding-left: 16px');
  165. expect(html).toContain('max-width: 300px');
  166. });