widget.spec.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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. ClientSession
  6. } from '@jupyterlab/apputils';
  7. import {
  8. Kernel
  9. } from '@jupyterlab/services';
  10. import {
  11. Message
  12. } from '@phosphor/messaging';
  13. import {
  14. Widget
  15. } from '@phosphor/widgets';
  16. import {
  17. IOutputAreaModel, OutputAreaModel, OutputAreaWidget
  18. } from '@jupyterlab/outputarea';
  19. import {
  20. createClientSession, defaultRenderMime, DEFAULT_OUTPUTS
  21. } from '../utils';
  22. /**
  23. * The default rendermime instance to use for testing.
  24. */
  25. const rendermime = defaultRenderMime();
  26. class LogOutputAreaWidget extends OutputAreaWidget {
  27. methods: string[] = [];
  28. protected onUpdateRequest(msg: Message): void {
  29. super.onUpdateRequest(msg);
  30. this.methods.push('onUpdateRequest');
  31. }
  32. protected onModelChanged(sender: IOutputAreaModel, args: IOutputAreaModel.ChangedArgs) {
  33. super.onModelChanged(sender, args);
  34. this.methods.push('onModelChanged');
  35. }
  36. }
  37. describe('outputarea/widget', () => {
  38. let widget: LogOutputAreaWidget;
  39. let model: OutputAreaModel;
  40. beforeEach(() => {
  41. model = new OutputAreaModel({ values: DEFAULT_OUTPUTS, trusted: true });
  42. widget = new LogOutputAreaWidget({ rendermime, model });
  43. });
  44. afterEach(() => {
  45. model.dispose();
  46. widget.dispose();
  47. });
  48. describe('OutputAreaWidget', () => {
  49. describe('#constructor()', () => {
  50. it('should create an output area widget', () => {
  51. expect(widget).to.be.an(OutputAreaWidget);
  52. expect(widget.hasClass('jp-OutputAreaWidget')).to.be(true);
  53. });
  54. it('should take an optional contentFactory', () => {
  55. let contentFactory = Object.create(OutputAreaWidget.defaultContentFactory);
  56. let widget = new OutputAreaWidget({ rendermime, contentFactory, model });
  57. expect(widget.contentFactory).to.be(contentFactory);
  58. });
  59. });
  60. describe('#model', () => {
  61. it('should be the model used by the widget', () => {
  62. expect(widget.model).to.be(model);
  63. });
  64. });
  65. describe('#rendermime', () => {
  66. it('should be the rendermime instance used by the widget', () => {
  67. expect(widget.rendermime).to.be(rendermime);
  68. });
  69. });
  70. describe('#contentFactory', () => {
  71. it('should be the contentFactory used by the widget', () => {
  72. expect(widget.contentFactory).to.be(OutputAreaWidget.defaultContentFactory);
  73. });
  74. });
  75. describe('#widgets', () => {
  76. it('should get the child widget at the specified index', () => {
  77. expect(widget.widgets[0]).to.be.a(Widget);
  78. });
  79. it('should get the number of child widgets', () => {
  80. expect(widget.widgets.length).to.be(DEFAULT_OUTPUTS.length - 1);
  81. widget.model.clear();
  82. expect(widget.widgets.length).to.be(0);
  83. });
  84. });
  85. describe('#collapsed', () => {
  86. it('should get the collapsed state of the widget', () => {
  87. expect(widget.collapsed).to.be(false);
  88. });
  89. it('should set the collapsed state of the widget', () => {
  90. widget.collapsed = true;
  91. expect(widget.collapsed).to.be(true);
  92. });
  93. it('should post an update request', (done) => {
  94. widget.collapsed = true;
  95. requestAnimationFrame(() => {
  96. expect(widget.methods).to.contain('onUpdateRequest');
  97. done();
  98. });
  99. });
  100. });
  101. describe('#fixedHeight', () => {
  102. it('should get the fixed height state of the widget', () => {
  103. expect(widget.fixedHeight).to.be(false);
  104. });
  105. it('should set the fixed height state of the widget', () => {
  106. widget.fixedHeight = true;
  107. expect(widget.fixedHeight).to.be(true);
  108. });
  109. it('should post an update request', (done) => {
  110. widget.fixedHeight = true;
  111. requestAnimationFrame(() => {
  112. expect(widget.methods).to.contain('onUpdateRequest');
  113. done();
  114. });
  115. });
  116. });
  117. describe('#dispose()', () => {
  118. it('should dispose of the resources held by the widget', () => {
  119. widget.dispose();
  120. expect(widget.isDisposed).to.be(true);
  121. widget.dispose();
  122. expect(widget.isDisposed).to.be(true);
  123. });
  124. });
  125. describe('#execute()', () => {
  126. let session: ClientSession;
  127. beforeEach(() => {
  128. return createClientSession().then(s => {
  129. session = s;
  130. return session.initialize();
  131. }).then(() => {
  132. return session.kernel.ready;
  133. });
  134. });
  135. afterEach(() => {
  136. return session.shutdown().then(() => {
  137. session.dispose();
  138. });
  139. });
  140. it('should execute code on a kernel and send outputs to the model', () => {
  141. return widget.execute('print("hello")', session).then(reply => {
  142. expect(reply.content.execution_count).to.be.ok();
  143. expect(reply.content.status).to.be('ok');
  144. });
  145. });
  146. it('should clear existing outputs', () => {
  147. widget.model.fromJSON(DEFAULT_OUTPUTS);
  148. return widget.execute('print("hello")', session).then(reply => {
  149. expect(reply.content.execution_count).to.be.ok();
  150. expect(model.length).to.be.lessThan(2);
  151. });
  152. });
  153. });
  154. describe('#onUpdateRequest()', () => {
  155. it('should set the appropriate classes on the widget', (done) => {
  156. widget.collapsed = true;
  157. widget.fixedHeight = true;
  158. requestAnimationFrame(() => {
  159. expect(widget.methods).to.contain('onUpdateRequest');
  160. expect(widget.hasClass('jp-mod-fixedHeight')).to.be(true);
  161. expect(widget.hasClass('jp-mod-collapsed')).to.be(true);
  162. done();
  163. });
  164. });
  165. });
  166. describe('#onModelChanged()', () => {
  167. it('should handle an added output', () => {
  168. widget.model.clear();
  169. widget.methods = [];
  170. widget.model.add(DEFAULT_OUTPUTS[0]);
  171. expect(widget.methods).to.contain('onModelChanged');
  172. expect(widget.widgets.length).to.be(1);
  173. });
  174. it('should handle a clear', () => {
  175. widget.model.fromJSON(DEFAULT_OUTPUTS);
  176. widget.methods = [];
  177. widget.model.clear();
  178. expect(widget.methods).to.contain('onModelChanged');
  179. expect(widget.widgets.length).to.be(0);
  180. });
  181. it('should handle a set', () => {
  182. widget.model.clear();
  183. widget.model.add(DEFAULT_OUTPUTS[0]);
  184. widget.methods = [];
  185. widget.model.add(DEFAULT_OUTPUTS[0]);
  186. expect(widget.methods).to.contain('onModelChanged');
  187. expect(widget.widgets.length).to.be(1);
  188. });
  189. });
  190. describe('.contentFactory', () => {
  191. describe('#createGutter()', () => {
  192. it('should create a gutter widget', () => {
  193. let factory = new OutputAreaWidget.ContentFactory();
  194. expect(factory.createGutter().executionCount).to.be(null);
  195. });
  196. });
  197. describe('#createStdin()', () => {
  198. it('should create a stdin widget', () => {
  199. return Kernel.startNew().then(kernel => {
  200. let factory = new OutputAreaWidget.ContentFactory();
  201. let options = {
  202. prompt: 'hello',
  203. password: false,
  204. kernel
  205. };
  206. expect(factory.createStdin(options)).to.be.a(Widget);
  207. kernel.dispose();
  208. });
  209. });
  210. });
  211. });
  212. describe('.defaultContentFactory', () => {
  213. it('should be a `contentFactory` instance', () => {
  214. expect(OutputAreaWidget.defaultContentFactory).to.be.an(OutputAreaWidget.ContentFactory);
  215. });
  216. });
  217. });
  218. });