rendermime.spec.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import expect = require('expect.js');
  4. import {
  5. Widget
  6. } from 'phosphor/lib/ui/widget';
  7. import {
  8. LatexRenderer, PDFRenderer, JavascriptRenderer,
  9. SVGRenderer, MarkdownRenderer, TextRenderer, HTMLRenderer, ImageRenderer
  10. } from '../../../lib/renderers';
  11. import {
  12. RenderMime
  13. } from '../../../lib/rendermime';
  14. import {
  15. defaultSanitizer
  16. } from '../../../lib/sanitizer';
  17. const TRANSFORMERS = [
  18. new JavascriptRenderer(),
  19. new MarkdownRenderer(),
  20. new HTMLRenderer(),
  21. new PDFRenderer(),
  22. new ImageRenderer(),
  23. new SVGRenderer(),
  24. new LatexRenderer(),
  25. new TextRenderer()
  26. ];
  27. export
  28. function defaultRenderMime(): RenderMime {
  29. let renderers: RenderMime.MimeMap<RenderMime.IRenderer> = {};
  30. let order: string[] = [];
  31. for (let t of TRANSFORMERS) {
  32. for (let m of t.mimetypes) {
  33. renderers[m] = t;
  34. order.push(m);
  35. }
  36. }
  37. let sanitizer = defaultSanitizer;
  38. return new RenderMime({ renderers, order, sanitizer });
  39. }
  40. describe('rendermime/index', () => {
  41. describe('RenderMime', () => {
  42. describe('#constructor()', () => {
  43. it('should accept a mapping and a default order', () => {
  44. let r = defaultRenderMime();
  45. expect(r instanceof RenderMime).to.be(true);
  46. });
  47. });
  48. describe('#render()', () => {
  49. it('should render a mimebundle', () => {
  50. let r = defaultRenderMime();
  51. let w = r.render({ bundle: { 'text/plain': 'foo' } });
  52. expect(w instanceof Widget).to.be(true);
  53. });
  54. it('should return `undefined` for an unregistered mime type', () => {
  55. let r = defaultRenderMime();
  56. let value = r.render({ bundle: { 'text/fizz': 'buzz' } });
  57. expect(value).to.be(void 0);
  58. });
  59. it('should render with the mimetype of highest precidence', () => {
  60. let bundle: RenderMime.MimeMap<string> = {
  61. 'text/plain': 'foo',
  62. 'text/html': '<h1>foo</h1>'
  63. };
  64. let r = defaultRenderMime();
  65. let w = r.render({ bundle, trusted: true });
  66. let el = w.node.firstChild as HTMLElement;
  67. expect(el.localName).to.be('h1');
  68. });
  69. it('should render the mimetype that is safe', () => {
  70. let bundle: RenderMime.MimeMap<string> = {
  71. 'text/plain': 'foo',
  72. 'text/javascript': 'window.x = 1',
  73. 'image/png': 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
  74. };
  75. let r = defaultRenderMime();
  76. let w = r.render({ bundle, trusted: false });
  77. let el = w.node.firstChild as HTMLElement;
  78. expect(el.localName).to.be('img');
  79. });
  80. it('should render the mimetype that is sanitizable', () => {
  81. let bundle: RenderMime.MimeMap<string> = {
  82. 'text/plain': 'foo',
  83. 'text/html': '<h1>foo</h1>'
  84. };
  85. let r = defaultRenderMime();
  86. let w = r.render({ bundle, trusted: false });
  87. let el = w.node.firstChild as HTMLElement;
  88. expect(el.localName).to.be('h1');
  89. });
  90. it('should sanitize html', () => {
  91. let bundle: RenderMime.MimeMap<string> = {
  92. 'text/html': '<h1>foo <script>window.x=1></scrip></h1>'
  93. };
  94. let r = defaultRenderMime();
  95. let widget = r.render({ bundle });
  96. expect(widget.node.innerHTML).to.be('<h1>foo </h1>');
  97. });
  98. it('should sanitize svg', () => {
  99. let bundle: RenderMime.MimeMap<string> = {
  100. 'image/svg+xml': '<svg><script>windox.x=1</script></svg>'
  101. };
  102. let r = defaultRenderMime();
  103. let widget = r.render({ bundle });
  104. expect(widget.node.innerHTML.indexOf('svg')).to.not.be(-1);
  105. expect(widget.node.innerHTML.indexOf('script')).to.be(-1);
  106. });
  107. });
  108. describe('#preferredMimetype()', () => {
  109. it('should find the preferred mimetype in a bundle', () => {
  110. let bundle: RenderMime.MimeMap<string> = {
  111. 'text/plain': 'foo',
  112. 'text/html': '<h1>foo</h1>'
  113. };
  114. let r = defaultRenderMime();
  115. expect(r.preferredMimetype(bundle)).to.be('text/html');
  116. });
  117. it('should return `undefined` if there are no registered mimetypes', () => {
  118. let r = defaultRenderMime();
  119. expect(r.preferredMimetype({ 'text/fizz': 'buzz' })).to.be(void 0);
  120. });
  121. it('should select the mimetype that is safe', () => {
  122. let bundle: RenderMime.MimeMap<string> = {
  123. 'text/plain': 'foo',
  124. 'text/javascript': 'window.x = 1',
  125. 'image/png': 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
  126. };
  127. let r = defaultRenderMime();
  128. expect(r.preferredMimetype(bundle)).to.be('image/png');
  129. });
  130. it('should render the mimetype that is sanitizable', () => {
  131. let bundle: RenderMime.MimeMap<string> = {
  132. 'text/plain': 'foo',
  133. 'text/html': '<h1>foo</h1>'
  134. };
  135. let r = defaultRenderMime();
  136. expect(r.preferredMimetype(bundle)).to.be('text/html');
  137. });
  138. });
  139. describe('#clone()', () => {
  140. it('should clone the rendermime instance with shallow copies of data', () => {
  141. let r = defaultRenderMime();
  142. let c = r.clone();
  143. expect(c.order).to.eql(r.order);
  144. let t = new TextRenderer();
  145. c.addRenderer('text/foo', t);
  146. expect(r).to.not.be(c);
  147. });
  148. });
  149. describe('#addRenderer()', () => {
  150. it('should add a renderer by mimetype', () => {
  151. let r = defaultRenderMime();
  152. let t = new TextRenderer();
  153. r.addRenderer('text/foo', t);
  154. let index = r.order.indexOf('text/foo');
  155. expect(index).to.be(0);
  156. });
  157. it('should take an optional order index', () => {
  158. let r = defaultRenderMime();
  159. let t = new TextRenderer();
  160. let len = r.order.length;
  161. r.addRenderer('text/foo', t, 0);
  162. let index = r.order.indexOf('text/foo');
  163. expect(index).to.be(0);
  164. expect(r.order.length).to.be(len + 1);
  165. });
  166. });
  167. describe('#removeRenderer()', () => {
  168. it('should remove a renderer by mimetype', () => {
  169. let r = defaultRenderMime();
  170. r.removeRenderer('text/html');
  171. let bundle: RenderMime.MimeMap<string> = {
  172. 'text/html': '<h1>foo</h1>'
  173. };
  174. expect(r.preferredMimetype(bundle)).to.be(void 0);
  175. });
  176. it('should be a no-op if the mimetype is not registered', () => {
  177. let r = defaultRenderMime();
  178. r.removeRenderer('text/foo');
  179. });
  180. });
  181. describe('#order', () => {
  182. it('should get the ordered list of mimetypes', () => {
  183. let r = defaultRenderMime();
  184. expect(r.order.indexOf('text/html')).to.not.be(-1);
  185. });
  186. it('should set the ordered list of mimetypes', () => {
  187. let r = defaultRenderMime();
  188. let order = r.order.reverse();
  189. r.order = order;
  190. expect(r.order).to.eql(order);
  191. });
  192. });
  193. });
  194. });