widget.spec.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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. UUID
  6. } from '@phosphor/coreutils';
  7. import {
  8. Contents, ServiceManager
  9. } from '@jupyterlab/services';
  10. import {
  11. Message, MessageLoop
  12. } from '@phosphor/messaging';
  13. import {
  14. Widget
  15. } from '@phosphor/widgets';
  16. import {
  17. Base64ModelFactory, Context, DocumentRegistry, DocumentWidget
  18. } from '@jupyterlab/docregistry';
  19. import {
  20. ImageViewer, ImageViewerFactory
  21. } from '@jupyterlab/imageviewer';
  22. import {
  23. createFileContext
  24. } from '../../utils';
  25. class LogImage extends ImageViewer {
  26. methods: string[] = [];
  27. protected onUpdateRequest(msg: Message): void {
  28. super.onUpdateRequest(msg);
  29. this.methods.push('onUpdateRequest');
  30. }
  31. protected onActivateRequest(msg: Message): void {
  32. super.onActivateRequest(msg);
  33. this.methods.push('onActivateRequest');
  34. }
  35. }
  36. /**
  37. * The common image model.
  38. */
  39. const IMAGE: Partial<Contents.IModel> = {
  40. path: UUID.uuid4() + '.png',
  41. type: 'file',
  42. mimetype: 'image/png',
  43. content: 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
  44. format: 'base64'
  45. };
  46. /**
  47. * The alternate content.
  48. */
  49. const OTHER = ('iVBORw0KGgoAAAANSUhEUgAAAAUA' +
  50. 'AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO' +
  51. '9TXL0Y4OHwAAAABJRU5ErkJggg=='
  52. );
  53. describe('ImageViewer', () => {
  54. let factory = new Base64ModelFactory();
  55. let context: Context<DocumentRegistry.IModel>;
  56. let manager: ServiceManager.IManager;
  57. let widget: LogImage;
  58. before(() => {
  59. manager = new ServiceManager();
  60. return manager.ready.then(() => {
  61. return manager.contents.save(IMAGE.path, IMAGE);
  62. });
  63. });
  64. beforeEach(() => {
  65. context = new Context({ manager, factory, path: IMAGE.path });
  66. widget = new LogImage(context);
  67. return context.initialize(false);
  68. });
  69. afterEach(() => {
  70. widget.dispose();
  71. });
  72. describe('#constructor()', () => {
  73. it('should create an ImageViewer', () => {
  74. expect(widget).to.be.an(ImageViewer);
  75. });
  76. it('should keep the title in sync with the file name', (done) => {
  77. let newPath = (IMAGE as any).path = UUID.uuid4() + '.png';
  78. expect(widget.title.label).to.be(context.path);
  79. context.pathChanged.connect(() => {
  80. expect(widget.title.label).to.be(newPath);
  81. done();
  82. });
  83. manager.contents.rename(context.path, newPath).catch(done);
  84. });
  85. it('should set the content after the context is ready', (done) => {
  86. context.ready.then(() => {
  87. MessageLoop.sendMessage(widget, Widget.Msg.UpdateRequest);
  88. let img = widget.node.querySelector('img') as HTMLImageElement;
  89. expect(img.src).to.contain(IMAGE.content);
  90. done();
  91. }).catch(done);
  92. });
  93. it('should handle a change to the content', (done) => {
  94. context.ready.then(() => {
  95. context.model.fromString(OTHER);
  96. MessageLoop.sendMessage(widget, Widget.Msg.UpdateRequest);
  97. let img = widget.node.querySelector('img') as HTMLImageElement;
  98. expect(img.src).to.contain(OTHER);
  99. done();
  100. }).catch(done);
  101. });
  102. });
  103. describe('#context', () => {
  104. it('should be the context associated with the widget', () => {
  105. expect(widget.context).to.be(context);
  106. });
  107. });
  108. describe('#scale', () => {
  109. it('should default to 1', () => {
  110. expect(widget.scale).to.be(1);
  111. });
  112. it('should be settable', () => {
  113. widget.scale = 0.5;
  114. expect(widget.scale).to.be(0.5);
  115. });
  116. });
  117. describe('#dispose()', () => {
  118. it('should dispose of the resources used by the widget', () => {
  119. expect(widget.isDisposed).to.be(false);
  120. widget.dispose();
  121. expect(widget.isDisposed).to.be(true);
  122. widget.dispose();
  123. expect(widget.isDisposed).to.be(true);
  124. });
  125. });
  126. describe('#onUpdateRequest()', () => {
  127. it('should render the image', () => {
  128. let img: HTMLImageElement = widget.node.querySelector('img');
  129. return widget.ready.then(() => {
  130. MessageLoop.sendMessage(widget, Widget.Msg.UpdateRequest);
  131. expect(widget.methods).to.contain('onUpdateRequest');
  132. expect(img.src).to.contain(IMAGE.content);
  133. });
  134. });
  135. });
  136. describe('#onActivateRequest()', () => {
  137. it('should focus the widget', () => {
  138. Widget.attach(widget, document.body);
  139. MessageLoop.sendMessage(widget, Widget.Msg.ActivateRequest);
  140. expect(widget.methods).to.contain('onActivateRequest');
  141. expect(widget.node.contains(document.activeElement)).to.be(true);
  142. });
  143. });
  144. });
  145. describe('ImageViewerFactory', () => {
  146. describe('#createNewWidget', () => {
  147. it('should create an image document widget', () => {
  148. let factory = new ImageViewerFactory({
  149. name: 'Image',
  150. modelName: 'base64',
  151. fileTypes: ['png'],
  152. defaultFor: ['png']
  153. });
  154. let context = createFileContext(IMAGE.path);
  155. let d = factory.createNew(context);
  156. expect(d).to.be.an(DocumentWidget);
  157. expect(d.content).to.be.an(ImageViewer);
  158. });
  159. });
  160. });