manager.spec.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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. ServiceManager
  6. } from '@jupyterlab/services';
  7. import {
  8. Widget
  9. } from '@phosphor/widgets';
  10. import {
  11. DocumentManager
  12. } from '@jupyterlab/docmanager';
  13. import {
  14. DocumentRegistry, TextModelFactory, ABCWidgetFactory
  15. } from '@jupyterlab/docregistry';
  16. import {
  17. dismissDialog
  18. } from '../utils';
  19. class DocWidget extends Widget implements DocumentRegistry.IReadyWidget {
  20. get ready(): Promise<void> {
  21. return Promise.resolve(undefined);
  22. }
  23. }
  24. class WidgetFactory extends ABCWidgetFactory<DocumentRegistry.IReadyWidget, DocumentRegistry.IModel> {
  25. protected createNewWidget(context: DocumentRegistry.Context): DocumentRegistry.IReadyWidget {
  26. let widget = new DocWidget();
  27. widget.addClass('WidgetFactory');
  28. return widget;
  29. }
  30. }
  31. describe('@jupyterlab/docmanager', () => {
  32. let manager: DocumentManager;
  33. let services: ServiceManager.IManager;
  34. let context: DocumentRegistry.Context;
  35. let widget: Widget;
  36. let modelFactory = new TextModelFactory();
  37. let widgetFactory = new WidgetFactory({
  38. name: 'test',
  39. fileExtensions: ['.txt'],
  40. canStartKernel: true,
  41. preferKernel: true
  42. });
  43. let openedWidget: Widget;
  44. before(() => {
  45. services = new ServiceManager();
  46. return services.ready;
  47. });
  48. beforeEach(() => {
  49. let registry = new DocumentRegistry();
  50. registry.addModelFactory(modelFactory);
  51. registry.addWidgetFactory(widgetFactory);
  52. manager = new DocumentManager({
  53. registry,
  54. manager: services,
  55. opener: {
  56. open: (widget: Widget) => {
  57. openedWidget = widget;
  58. }
  59. }
  60. });
  61. });
  62. afterEach(() => {
  63. manager.dispose();
  64. });
  65. describe('DocumentWidgetManager', () => {
  66. describe('#constructor()', () => {
  67. it('should create a new document manager', () => {
  68. expect(manager).to.be.a(DocumentManager);
  69. });
  70. });
  71. describe('#isDisposed', () => {
  72. it('should test whether the manager is disposed', () => {
  73. expect(manager.isDisposed).to.be(false);
  74. manager.dispose();
  75. expect(manager.isDisposed).to.be(true);
  76. });
  77. });
  78. describe('#dispose()', () => {
  79. it('should dispose of the resources used by the manager', () => {
  80. expect(manager.isDisposed).to.be(false);
  81. manager.dispose();
  82. expect(manager.isDisposed).to.be(true);
  83. manager.dispose();
  84. expect(manager.isDisposed).to.be(true);
  85. });
  86. });
  87. describe('#services', () => {
  88. it('should get the service manager for the manager', () => {
  89. expect(manager.services).to.be.a(ServiceManager);
  90. });
  91. });
  92. describe('#registry', () => {
  93. it('should get the registry used by the manager', () => {
  94. expect(manager.registry).to.be.a(DocumentRegistry);
  95. });
  96. });
  97. describe('#open()', () => {
  98. it('should open a file and return the widget used to view it', () => {
  99. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  100. widget = manager.open(model.path);
  101. expect(widget.hasClass('WidgetFactory')).to.be(true);
  102. return dismissDialog();
  103. });
  104. });
  105. it('should start a kernel if one is given', () => {
  106. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  107. return services.sessions.startNew({ path: model.path });
  108. }).then(session => {
  109. let id = session.kernel.id;
  110. widget = manager.open(session.path, 'default', { id });
  111. context = manager.contextForWidget(widget);
  112. return context.ready;
  113. }).then(() => {
  114. expect(context.session.kernel).to.be.ok();
  115. return context.session.shutdown();
  116. });
  117. });
  118. it('should not auto-start a kernel if there is none given', () => {
  119. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  120. widget = manager.open(model.path, 'default');
  121. context = manager.contextForWidget(widget);
  122. return dismissDialog();
  123. }).then(() => {
  124. expect(context.session.kernel).to.be(null);
  125. });
  126. });
  127. it('should return undefined if the factory is not found', () => {
  128. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  129. widget = manager.open(model.path, 'foo');
  130. expect(widget).to.be(void 0);
  131. });
  132. });
  133. it('should return undefined if the factory has no model factory', () => {
  134. let widgetFactory2 = new WidgetFactory({
  135. name: 'test',
  136. modelName: 'foo',
  137. fileExtensions: ['.txt']
  138. });
  139. manager.registry.addWidgetFactory(widgetFactory2);
  140. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  141. widget = manager.open(model.path, 'foo');
  142. expect(widget).to.be(void 0);
  143. });
  144. });
  145. });
  146. describe('#createNew()', () => {
  147. it('should open a file and return the widget used to view it', () => {
  148. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  149. widget = manager.createNew(model.path);
  150. expect(widget.hasClass('WidgetFactory')).to.be(true);
  151. return dismissDialog();
  152. });
  153. });
  154. it('should start a kernel if one is given', () => {
  155. let id: string;
  156. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  157. return services.sessions.startNew({ path: model.path });
  158. }).then(session => {
  159. id = session.kernel.id;
  160. widget = manager.createNew(session.path, 'default', { id });
  161. context = manager.contextForWidget(widget);
  162. return context.ready;
  163. }).then(() => {
  164. expect(context.session.kernel.id).to.be(id);
  165. return context.session.shutdown();
  166. });
  167. });
  168. it('should not start a kernel if not given', () => {
  169. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  170. widget = manager.createNew(model.path, 'default');
  171. context = manager.contextForWidget(widget);
  172. return dismissDialog();
  173. }).then(() => {
  174. expect(context.session.kernel).to.be(null);
  175. });
  176. });
  177. it('should return undefined if the factory is not found', () => {
  178. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  179. widget = manager.createNew(model.path, 'foo');
  180. expect(widget).to.be(void 0);
  181. });
  182. });
  183. it('should return undefined if the factory has no model factory', () => {
  184. let widgetFactory2 = new WidgetFactory({
  185. name: 'test',
  186. modelName: 'foo',
  187. fileExtensions: ['.txt']
  188. });
  189. manager.registry.addWidgetFactory(widgetFactory2);
  190. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  191. widget = manager.createNew(model.path, 'foo');
  192. expect(widget).to.be(void 0);
  193. });
  194. });
  195. });
  196. describe('#findWidget()', () => {
  197. it('should find a widget given a file and a widget name', () => {
  198. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  199. widget = manager.createNew(model.path);
  200. expect(manager.findWidget(model.path, 'test')).to.be(widget);
  201. return dismissDialog();
  202. });
  203. });
  204. it('should find a widget given a file', () => {
  205. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  206. widget = manager.createNew(model.path);
  207. expect(manager.findWidget(model.path)).to.be(widget);
  208. return dismissDialog();
  209. });
  210. });
  211. it('should fail to find a widget', () => {
  212. expect(manager.findWidget('foo')).to.be(void 0);
  213. });
  214. });
  215. describe('#contextForWidget()', () => {
  216. it('should find the context for a widget', () => {
  217. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  218. widget = manager.createNew(model.path);
  219. context = manager.contextForWidget(widget);
  220. expect(context.path).to.be(model.path);
  221. return dismissDialog();
  222. });
  223. });
  224. it('should fail to find the context for the widget', () => {
  225. widget = new Widget();
  226. expect(manager.contextForWidget(widget)).to.be(undefined);
  227. });
  228. });
  229. describe('#cloneWidget()', () => {
  230. it('should clone the given widget', () => {
  231. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  232. widget = manager.createNew(model.path);
  233. let clone = manager.cloneWidget(widget);
  234. expect(manager.contextForWidget(widget)).to.be(manager.contextForWidget(clone));
  235. return dismissDialog();
  236. });
  237. });
  238. it('should return undefined if the source widget is not managed', () => {
  239. widget = new Widget();
  240. expect(manager.cloneWidget(widget)).to.be(void 0);
  241. });
  242. });
  243. describe('#closeFile()', () => {
  244. it('should close the widgets associated with a given path', () => {
  245. let called = 0;
  246. let path = '';
  247. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  248. path = model.path;
  249. widget = manager.createNew(path);
  250. let clone = manager.cloneWidget(widget);
  251. widget.disposed.connect(() => { called++; });
  252. clone.disposed.connect(() => { called++; });
  253. return dismissDialog();
  254. }).then(() => {
  255. return manager.closeFile(path);
  256. }).then(() => {
  257. expect(called).to.be(2);
  258. });
  259. });
  260. it('should be a no-op if there are no open files on that path', () => {
  261. return manager.closeFile('foo');
  262. });
  263. });
  264. describe('#closeAll()', () => {
  265. it('should close all of the open documents', () => {
  266. let called = 0;
  267. let path = '';
  268. return services.contents.newUntitled({ type: 'file', ext: '.txt'}).then(model => {
  269. path = model.path;
  270. let widget0 = manager.createNew(path);
  271. widget0.disposed.connect(() => { called++; });
  272. return dismissDialog();
  273. }).then(() => {
  274. let widget1 = manager.createNew(path);
  275. widget1.disposed.connect(() => { called++; });
  276. return dismissDialog();
  277. }).then(() => {
  278. return manager.closeAll();
  279. }).then(() => {
  280. expect(called).to.be(2);
  281. });
  282. });
  283. it('should be a no-op if there are no open documents', () => {
  284. return manager.closeAll();
  285. });
  286. });
  287. });
  288. });