widget.spec.ts 5.0 KB

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