registry.spec.ts 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import {
  4. ABCWidgetFactory,
  5. Base64ModelFactory,
  6. DocumentRegistry,
  7. DocumentWidget,
  8. IDocumentWidget
  9. } from '@jupyterlab/docregistry';
  10. import { toArray } from '@lumino/algorithm';
  11. import { UUID } from '@lumino/coreutils';
  12. import { DisposableDelegate, IDisposable } from '@lumino/disposable';
  13. import { Widget } from '@lumino/widgets';
  14. class WidgetFactory extends ABCWidgetFactory<IDocumentWidget> {
  15. protected createNewWidget(
  16. context: DocumentRegistry.Context
  17. ): IDocumentWidget {
  18. const content = new Widget();
  19. const widget = new DocumentWidget({ content, context });
  20. widget.addClass('WidgetFactory');
  21. return widget;
  22. }
  23. }
  24. class WidgetExtension implements DocumentRegistry.WidgetExtension {
  25. createNew(widget: Widget, context: DocumentRegistry.Context): IDisposable {
  26. return new DisposableDelegate(() => undefined);
  27. }
  28. }
  29. function createFactory(modelName?: string) {
  30. return new WidgetFactory({
  31. name: UUID.uuid4(),
  32. modelName: modelName || 'text',
  33. fileTypes: ['text', 'foobar', 'baz'],
  34. defaultFor: ['text', 'foobar'],
  35. defaultRendered: ['baz']
  36. });
  37. }
  38. describe('docregistry/registry', () => {
  39. describe('DocumentRegistry', () => {
  40. let registry: DocumentRegistry;
  41. beforeEach(() => {
  42. registry = new DocumentRegistry();
  43. registry.addFileType({
  44. name: 'foobar',
  45. extensions: ['.foo.bar']
  46. });
  47. registry.addFileType({
  48. name: 'baz',
  49. extensions: ['.baz']
  50. });
  51. });
  52. afterEach(() => {
  53. registry.dispose();
  54. });
  55. describe('#isDisposed', () => {
  56. it('should get whether the registry has been disposed', () => {
  57. expect(registry.isDisposed).toBe(false);
  58. registry.dispose();
  59. expect(registry.isDisposed).toBe(true);
  60. });
  61. });
  62. describe('#dispose()', () => {
  63. it('should dispose of the resources held by the registry', () => {
  64. registry.addFileType({ name: 'notebook', extensions: ['.ipynb'] });
  65. registry.dispose();
  66. expect(registry.isDisposed).toBe(true);
  67. });
  68. it('should be safe to call multiple times', () => {
  69. registry.dispose();
  70. registry.dispose();
  71. expect(registry.isDisposed).toBe(true);
  72. });
  73. });
  74. describe('#addWidgetFactory()', () => {
  75. it('should add the widget factory to the registry', () => {
  76. const factory = createFactory();
  77. registry.addWidgetFactory(factory);
  78. expect(registry.getWidgetFactory(factory.name)).toBe(factory);
  79. expect(registry.getWidgetFactory(factory.name.toUpperCase())).toBe(
  80. factory
  81. );
  82. });
  83. it('should become the global default if `*` is given as a defaultFor', () => {
  84. const factory = new WidgetFactory({
  85. name: 'global',
  86. fileTypes: ['*'],
  87. defaultFor: ['*']
  88. });
  89. registry.addWidgetFactory(factory);
  90. expect(registry.defaultWidgetFactory('*').name).toBe('global');
  91. });
  92. it('should override an existing global default', () => {
  93. registry.addWidgetFactory(
  94. new WidgetFactory({
  95. name: 'global',
  96. fileTypes: ['*'],
  97. defaultFor: ['*']
  98. })
  99. );
  100. const factory = new WidgetFactory({
  101. name: 'bar',
  102. fileTypes: ['*'],
  103. defaultFor: ['*']
  104. });
  105. registry.addWidgetFactory(factory);
  106. expect(registry.defaultWidgetFactory('*').name).toBe('bar');
  107. });
  108. it('should override an existing extension default', () => {
  109. registry.addWidgetFactory(createFactory());
  110. const factory = createFactory();
  111. registry.addWidgetFactory(factory);
  112. expect(registry.defaultWidgetFactory('a.foo.bar')).toBe(factory);
  113. });
  114. it('should be removed from the registry when disposed', () => {
  115. const factory = createFactory();
  116. const disposable = registry.addWidgetFactory(factory);
  117. disposable.dispose();
  118. expect(registry.getWidgetFactory('test')).toBeUndefined();
  119. });
  120. it('should throw for an invalid factory name', () => {
  121. expect(() => {
  122. registry.addWidgetFactory(
  123. new WidgetFactory({
  124. name: 'default',
  125. fileTypes: [],
  126. defaultFor: []
  127. })
  128. );
  129. }).toThrowError(/Invalid/);
  130. expect(() => {
  131. registry.addWidgetFactory(
  132. new WidgetFactory({
  133. name: '',
  134. fileTypes: [],
  135. defaultFor: []
  136. })
  137. );
  138. }).toThrowError(/Invalid/);
  139. });
  140. });
  141. describe('#addModelFactory()', () => {
  142. it('should add the model factory to the registry', () => {
  143. const factory = new Base64ModelFactory();
  144. registry.addModelFactory(factory);
  145. });
  146. it('should be a no-op a factory with the given `name` is already registered', () => {
  147. const factory = new Base64ModelFactory();
  148. registry.addModelFactory(factory);
  149. const disposable = registry.addModelFactory(new Base64ModelFactory());
  150. disposable.dispose();
  151. });
  152. it('should be a no-op if the same factory is already registered', () => {
  153. const factory = new Base64ModelFactory();
  154. registry.addModelFactory(factory);
  155. const disposable = registry.addModelFactory(factory);
  156. disposable.dispose();
  157. });
  158. it('should be removed from the registry when disposed', () => {
  159. const factory = new Base64ModelFactory();
  160. const disposable = registry.addModelFactory(factory);
  161. disposable.dispose();
  162. });
  163. });
  164. describe('#addWidgetExtension()', () => {
  165. it('should add a widget extension to the registry', () => {
  166. const extension = new WidgetExtension();
  167. registry.addWidgetExtension('foo', extension);
  168. expect(registry.widgetExtensions('foo').next()).toBe(extension);
  169. });
  170. it('should be a no-op if the extension is already registered for a given widget factory', () => {
  171. const extension = new WidgetExtension();
  172. registry.addWidgetExtension('foo', extension);
  173. const disposable = registry.addWidgetExtension('foo', extension);
  174. disposable.dispose();
  175. expect(registry.widgetExtensions('foo').next()).toBe(extension);
  176. });
  177. it('should be removed from the registry when disposed', () => {
  178. const extension = new WidgetExtension();
  179. const disposable = registry.addWidgetExtension('foo', extension);
  180. disposable.dispose();
  181. expect(toArray(registry.widgetExtensions('foo')).length).toBe(0);
  182. });
  183. });
  184. describe('#addFileType()', () => {
  185. it('should add a file type to the document registry', () => {
  186. registry = new DocumentRegistry({ initialFileTypes: [] });
  187. const fileType = { name: 'notebook', extensions: ['.ipynb'] };
  188. registry.addFileType(fileType);
  189. expect(registry.fileTypes().next()!.name).toBe(fileType.name);
  190. });
  191. it('should be removed from the registry when disposed', () => {
  192. registry = new DocumentRegistry({ initialFileTypes: [] });
  193. const fileType = { name: 'notebook', extensions: ['.ipynb'] };
  194. const disposable = registry.addFileType(fileType);
  195. disposable.dispose();
  196. expect(toArray(registry.fileTypes()).length).toBe(0);
  197. });
  198. it('should be a no-op if a file type of the same name is registered', () => {
  199. registry = new DocumentRegistry({ initialFileTypes: [] });
  200. const fileType = { name: 'notebook', extensions: ['.ipynb'] };
  201. registry.addFileType(fileType);
  202. const disposable = registry.addFileType(fileType);
  203. disposable.dispose();
  204. expect(registry.fileTypes().next()!.name).toBe(fileType.name);
  205. });
  206. it('should add a file type to some factories', () => {
  207. registry = new DocumentRegistry({ initialFileTypes: [] });
  208. const factory = createFactory();
  209. registry.addWidgetFactory(factory);
  210. const gFactory = new WidgetFactory({
  211. name: 'global',
  212. fileTypes: ['*'],
  213. defaultFor: ['*']
  214. });
  215. registry.addWidgetFactory(gFactory);
  216. expect(registry.defaultWidgetFactory('dummy.test').name).toEqual(
  217. gFactory.name
  218. );
  219. const fileType = { name: 'test-file', extensions: ['.test'] };
  220. registry.addFileType(fileType, [factory.name]);
  221. expect(registry.defaultWidgetFactory('dummy.test').name).toEqual(
  222. factory.name
  223. );
  224. });
  225. it('should add a file type to some factories without changing the default', () => {
  226. const factory = createFactory();
  227. registry.addWidgetFactory(factory);
  228. const gFactory = new WidgetFactory({
  229. name: 'global',
  230. fileTypes: ['*'],
  231. defaultFor: ['*']
  232. });
  233. registry.addWidgetFactory(gFactory);
  234. expect(registry.defaultWidgetFactory('dummy.foo.bar').name).toEqual(
  235. factory.name
  236. );
  237. const newFactory = new WidgetFactory({
  238. name: 'new-factory',
  239. fileTypes: ['new-foobar']
  240. });
  241. registry.addWidgetFactory(newFactory);
  242. const fileType = { name: 'test-file', extensions: ['.foo.bar'] };
  243. registry.addFileType(fileType, [newFactory.name]);
  244. expect(registry.defaultWidgetFactory('dummy.foo.bar').name).toEqual(
  245. factory.name
  246. );
  247. expect(
  248. registry.preferredWidgetFactories('dummy.foo.bar').map(f => f.name)
  249. ).toContain(newFactory.name);
  250. });
  251. it('should remove the link to factory when disposed', () => {
  252. registry = new DocumentRegistry({ initialFileTypes: [] });
  253. const factory = createFactory();
  254. registry.addWidgetFactory(factory);
  255. const gFactory = new WidgetFactory({
  256. name: 'global',
  257. fileTypes: ['*'],
  258. defaultFor: ['*']
  259. });
  260. registry.addWidgetFactory(gFactory);
  261. const fileType = { name: 'test-file', extensions: ['.test'] };
  262. const disposable = registry.addFileType(fileType, [factory.name]);
  263. disposable.dispose();
  264. expect(registry.defaultWidgetFactory('dummy.test').name).toBe(
  265. gFactory.name
  266. );
  267. });
  268. it('should remove the link to factory when disposed without changing the default', () => {
  269. const factory = createFactory();
  270. registry.addWidgetFactory(factory);
  271. const gFactory = new WidgetFactory({
  272. name: 'global',
  273. fileTypes: ['*'],
  274. defaultFor: ['*']
  275. });
  276. registry.addWidgetFactory(gFactory);
  277. const newFactory = new WidgetFactory({
  278. name: 'new-factory',
  279. fileTypes: ['new-foobar']
  280. });
  281. registry.addWidgetFactory(newFactory);
  282. const fileType = { name: 'test-file', extensions: ['.foo.bar'] };
  283. const disposable = registry.addFileType(fileType, [newFactory.name]);
  284. disposable.dispose();
  285. expect(registry.defaultWidgetFactory('dummy.foo.bar').name).toEqual(
  286. factory.name
  287. );
  288. expect(
  289. registry.preferredWidgetFactories('dummy.foo.bar').map(f => f.name)
  290. ).not.toContain(newFactory.name);
  291. });
  292. });
  293. describe('#preferredWidgetFactories()', () => {
  294. beforeEach(() => {
  295. registry.addFileType({
  296. name: 'tablejson',
  297. extensions: ['.table.json']
  298. });
  299. });
  300. it('should give the valid registered widget factories', () => {
  301. expect(toArray(registry.preferredWidgetFactories('foo.txt'))).toEqual(
  302. []
  303. );
  304. const factory = createFactory();
  305. registry.addWidgetFactory(factory);
  306. const gFactory = new WidgetFactory({
  307. name: 'global',
  308. fileTypes: ['*'],
  309. defaultFor: ['*']
  310. });
  311. registry.addWidgetFactory(gFactory);
  312. const factories = registry.preferredWidgetFactories('a.foo.bar');
  313. expect(toArray(factories)).toEqual([factory, gFactory]);
  314. });
  315. it('should not list a factory whose model is not registered', () => {
  316. registry.addWidgetFactory(createFactory('foobar'));
  317. expect(registry.preferredWidgetFactories('a.foo.bar').length).toEqual(
  318. 0
  319. );
  320. });
  321. it('should select the factory for a given extension', () => {
  322. const factory = createFactory();
  323. registry.addWidgetFactory(factory);
  324. const mdFactory = new WidgetFactory({
  325. name: 'markdown',
  326. fileTypes: ['markdown']
  327. });
  328. registry.addWidgetFactory(mdFactory);
  329. expect(registry.preferredWidgetFactories('a.txt')[0]).toBe(factory);
  330. expect(registry.preferredWidgetFactories('a.md')[0]).toBe(mdFactory);
  331. });
  332. it('should respect the priority order', () => {
  333. const factory = createFactory();
  334. registry.addWidgetFactory(factory);
  335. const gFactory = new WidgetFactory({
  336. name: 'global',
  337. fileTypes: ['*'],
  338. defaultFor: ['*']
  339. });
  340. registry.addWidgetFactory(gFactory);
  341. const mdFactory = new WidgetFactory({
  342. name: 'markdown',
  343. fileTypes: ['markdown']
  344. });
  345. registry.addWidgetFactory(mdFactory);
  346. const factories = registry.preferredWidgetFactories('a.txt');
  347. expect(toArray(factories)).toEqual([factory, gFactory]);
  348. });
  349. it('should list a default rendered factory after the default factory', () => {
  350. const factory = createFactory();
  351. registry.addWidgetFactory(factory);
  352. const gFactory = new WidgetFactory({
  353. name: 'global',
  354. fileTypes: ['*'],
  355. defaultFor: ['*']
  356. });
  357. registry.addWidgetFactory(gFactory);
  358. const mdFactory = new WidgetFactory({
  359. name: 'markdown',
  360. fileTypes: ['markdown'],
  361. defaultRendered: ['markdown']
  362. });
  363. registry.addWidgetFactory(mdFactory);
  364. const factories = registry.preferredWidgetFactories('a.md');
  365. expect(factories).toEqual([mdFactory, gFactory]);
  366. });
  367. it('should handle multi-part extensions', () => {
  368. const factory = createFactory();
  369. registry.addWidgetFactory(factory);
  370. const tFactory = new WidgetFactory({
  371. name: 'table',
  372. fileTypes: ['tablejson']
  373. });
  374. registry.addWidgetFactory(tFactory);
  375. const jFactory = new WidgetFactory({
  376. name: 'json',
  377. fileTypes: ['json']
  378. });
  379. registry.addWidgetFactory(jFactory);
  380. let factories = registry.preferredWidgetFactories('foo.table.json');
  381. expect(toArray(factories)).toEqual([tFactory, jFactory]);
  382. factories = registry.preferredWidgetFactories('foo.json');
  383. expect(toArray(factories)).toEqual([jFactory]);
  384. });
  385. it('should handle just a multi-part extension', () => {
  386. const factory = new WidgetFactory({
  387. name: 'table',
  388. fileTypes: ['tablejson']
  389. });
  390. registry.addWidgetFactory(factory);
  391. let factories = registry.preferredWidgetFactories('foo.table.json');
  392. expect(toArray(factories)).toEqual([factory]);
  393. factories = registry.preferredWidgetFactories('foo.json');
  394. expect(toArray(factories)).toEqual([]);
  395. });
  396. });
  397. describe('#defaultWidgetFactory()', () => {
  398. it('should get the default widget factory for a given extension', () => {
  399. const factory = createFactory();
  400. registry.addWidgetFactory(factory);
  401. const gFactory = new WidgetFactory({
  402. name: 'global',
  403. fileTypes: ['*'],
  404. defaultFor: ['*']
  405. });
  406. registry.addWidgetFactory(gFactory);
  407. const mdFactory = new WidgetFactory({
  408. name: 'markdown',
  409. fileTypes: ['markdown'],
  410. defaultFor: ['markdown']
  411. });
  412. registry.addWidgetFactory(mdFactory);
  413. expect(registry.defaultWidgetFactory('a.foo.bar')).toBe(factory);
  414. expect(registry.defaultWidgetFactory('a.md')).toBe(mdFactory);
  415. expect(registry.defaultWidgetFactory()).toBe(gFactory);
  416. });
  417. });
  418. describe('#setDefaultWidgetFactory()', () => {
  419. it('should override the default widget factory for a file type', () => {
  420. const mdFactory = new WidgetFactory({
  421. name: 'markdown',
  422. fileTypes: ['markdown', 'foobar'],
  423. defaultFor: []
  424. });
  425. registry.addWidgetFactory(mdFactory);
  426. registry.setDefaultWidgetFactory('foobar', 'markdown');
  427. expect(registry.defaultWidgetFactory('a.foo.bar')).toBe(mdFactory);
  428. });
  429. it('should revert to the default widget factory when unset', () => {
  430. const factory = createFactory();
  431. registry.addWidgetFactory(factory);
  432. const mdFactory = new WidgetFactory({
  433. name: 'markdown',
  434. fileTypes: ['markdown', 'foobar'],
  435. defaultFor: []
  436. });
  437. registry.addWidgetFactory(mdFactory);
  438. registry.setDefaultWidgetFactory('foobar', 'markdown');
  439. registry.setDefaultWidgetFactory('foobar', undefined);
  440. expect(registry.defaultWidgetFactory('a.foo.bar')).toBe(factory);
  441. });
  442. it('should throw if the factory or file type do not exist', () => {
  443. const factory = createFactory();
  444. registry.addWidgetFactory(factory);
  445. expect(() => {
  446. registry.setDefaultWidgetFactory('foobar', 'fake');
  447. }).toThrowError(/Cannot find/);
  448. expect(() => {
  449. registry.setDefaultWidgetFactory('fake', undefined);
  450. }).toThrowError(/Cannot find/);
  451. });
  452. it('should throw if the factory cannot render a file type', () => {
  453. const mdFactory = new WidgetFactory({
  454. name: 'markdown',
  455. fileTypes: ['markdown'],
  456. defaultFor: []
  457. });
  458. registry.addWidgetFactory(mdFactory);
  459. expect(() => {
  460. registry.setDefaultWidgetFactory('foobar', 'markdown');
  461. }).toThrowError(/cannot view/);
  462. });
  463. it('should revert to the default widget factory if the override is removed', () => {
  464. const factory = createFactory();
  465. registry.addWidgetFactory(factory);
  466. const mdFactory = new WidgetFactory({
  467. name: 'markdown',
  468. fileTypes: ['markdown', 'foobar'],
  469. defaultFor: []
  470. });
  471. const disposable = registry.addWidgetFactory(mdFactory);
  472. registry.setDefaultWidgetFactory('foobar', 'markdown');
  473. disposable.dispose();
  474. expect(registry.defaultWidgetFactory('a.foo.bar')).toBe(factory);
  475. });
  476. });
  477. describe('#defaultRenderedWidgetFactory()', () => {
  478. it('should get the default rendered widget factory for a given extension', () => {
  479. const factory = createFactory();
  480. registry.addWidgetFactory(factory);
  481. const mdFactory = new WidgetFactory({
  482. name: 'markdown',
  483. fileTypes: ['markdown'],
  484. defaultRendered: ['markdown']
  485. });
  486. registry.addWidgetFactory(mdFactory);
  487. expect(registry.defaultRenderedWidgetFactory('a.baz')).toBe(factory);
  488. expect(registry.defaultRenderedWidgetFactory('a.md')).toBe(mdFactory);
  489. });
  490. it('should get the default widget factory if no default rendered factory is registered', () => {
  491. const gFactory = new WidgetFactory({
  492. name: 'global',
  493. fileTypes: ['*'],
  494. defaultFor: ['*']
  495. });
  496. registry.addWidgetFactory(gFactory);
  497. expect(registry.defaultRenderedWidgetFactory('a.md')).toBe(gFactory);
  498. });
  499. });
  500. describe('#fileTypes()', () => {
  501. it('should get the registered file types', () => {
  502. registry = new DocumentRegistry({ initialFileTypes: [] });
  503. expect(toArray(registry.fileTypes()).length).toBe(0);
  504. const fileTypes = [
  505. { name: 'notebook', extensions: ['.ipynb'] },
  506. { name: 'python', extensions: ['.py'] },
  507. { name: 'table', extensions: ['.table.json'] }
  508. ];
  509. registry.addFileType(fileTypes[0]);
  510. registry.addFileType(fileTypes[1]);
  511. registry.addFileType(fileTypes[2]);
  512. const values = registry.fileTypes();
  513. expect(values.next()!.name).toBe(fileTypes[0].name);
  514. expect(values.next()!.name).toBe(fileTypes[1].name);
  515. expect(values.next()!.name).toBe(fileTypes[2].name);
  516. });
  517. });
  518. describe('#getFileType()', () => {
  519. it('should get a file type by name', () => {
  520. expect(registry.getFileType('notebook')).toBeTruthy();
  521. expect(registry.getFileType('python')).toBeTruthy();
  522. expect(registry.getFileType('fizzbuzz')).toBeUndefined();
  523. });
  524. });
  525. describe('#getKernelPreference()', () => {
  526. it('should get a kernel preference', () => {
  527. registry.addWidgetFactory(createFactory());
  528. registry.addWidgetFactory(
  529. new WidgetFactory({
  530. name: 'python',
  531. fileTypes: ['python'],
  532. preferKernel: true,
  533. canStartKernel: true
  534. })
  535. );
  536. registry.addWidgetFactory(
  537. new WidgetFactory({
  538. name: 'global',
  539. fileTypes: ['*'],
  540. defaultFor: ['*']
  541. })
  542. );
  543. let pref = registry.getKernelPreference('.c', 'global');
  544. expect(pref!.language).toBe('clike');
  545. expect(pref!.shouldStart).toBe(false);
  546. expect(pref!.canStart).toBe(false);
  547. pref = registry.getKernelPreference('.py', 'python');
  548. expect(pref!.language).toBe('python');
  549. expect(pref!.shouldStart).toBe(true);
  550. expect(pref!.canStart).toBe(true);
  551. pref = registry.getKernelPreference('.py', 'baz');
  552. expect(pref).toBeUndefined();
  553. });
  554. });
  555. describe('#getModelFactory()', () => {
  556. it('should get a registered model factory by name', () => {
  557. const mFactory = new Base64ModelFactory();
  558. registry.addModelFactory(mFactory);
  559. expect(registry.getModelFactory('base64')).toBe(mFactory);
  560. });
  561. });
  562. describe('#getWidgetFactory()', () => {
  563. it('should get a widget factory by name', () => {
  564. registry.addModelFactory(new Base64ModelFactory());
  565. const factory = createFactory();
  566. registry.addWidgetFactory(factory);
  567. const mdFactory = new WidgetFactory({
  568. name: 'markdown',
  569. fileTypes: ['markdown']
  570. });
  571. registry.addWidgetFactory(mdFactory);
  572. expect(registry.getWidgetFactory(factory.name)).toBe(factory);
  573. expect(registry.getWidgetFactory('markdown')).toBe(mdFactory);
  574. expect(registry.getWidgetFactory('baz')).toBeUndefined();
  575. });
  576. });
  577. describe('#widgetExtensions()', () => {
  578. it('should get the registered extensions for a given widget', () => {
  579. const foo = new WidgetExtension();
  580. const bar = new WidgetExtension();
  581. registry.addWidgetExtension('fizz', foo);
  582. registry.addWidgetExtension('fizz', bar);
  583. registry.addWidgetExtension('buzz', foo);
  584. const fizz = toArray(registry.widgetExtensions('fizz'));
  585. expect(fizz[0]).toBe(foo);
  586. expect(fizz[1]).toBe(bar);
  587. expect(fizz.length).toBe(2);
  588. const buzz = toArray(registry.widgetExtensions('buzz'));
  589. expect(buzz[0]).toBe(foo);
  590. expect(toArray(buzz).length).toBe(1);
  591. expect(registry.widgetExtensions('baz').next()).toBeUndefined();
  592. });
  593. });
  594. describe('#getFileTypeForModel()', () => {
  595. beforeEach(() => {
  596. DocumentRegistry.getDefaultFileTypes().forEach(ft => {
  597. registry.addFileType(ft);
  598. });
  599. });
  600. it('should handle a directory', () => {
  601. const ft = registry.getFileTypeForModel({
  602. type: 'directory'
  603. });
  604. expect(ft.name).toBe('directory');
  605. });
  606. it('should handle a notebook', () => {
  607. const ft = registry.getFileTypeForModel({
  608. type: 'notebook'
  609. });
  610. expect(ft.name).toBe('notebook');
  611. });
  612. it('should handle a python file', () => {
  613. const ft = registry.getFileTypeForModel({
  614. name: 'foo.py'
  615. });
  616. expect(ft.name).toBe('python');
  617. });
  618. it('should handle an unknown file', () => {
  619. const ft = registry.getFileTypeForModel({
  620. name: 'foo.bar'
  621. });
  622. expect(ft.name).toBe('text');
  623. });
  624. it('should get the most specific extension', () => {
  625. [
  626. { name: 'json', extensions: ['.json'] },
  627. { name: 'vega', extensions: ['.vg.json'] }
  628. ].forEach(ft => {
  629. registry.addFileType(ft);
  630. });
  631. const ft = registry.getFileTypeForModel({
  632. name: 'foo.vg.json'
  633. });
  634. expect(ft.name).toBe('vega');
  635. });
  636. it('should be case insensitive', () => {
  637. const ft = registry.getFileTypeForModel({
  638. name: 'foo.PY'
  639. });
  640. expect(ft.name).toBe('python');
  641. });
  642. });
  643. describe('#getFileTypesForPath()', () => {
  644. beforeEach(() => {
  645. DocumentRegistry.getDefaultFileTypes().forEach(ft => {
  646. registry.addFileType(ft);
  647. });
  648. });
  649. it('should handle a notebook', () => {
  650. const ft = registry.getFileTypesForPath('foo/bar/baz.ipynb');
  651. expect(ft[0].name).toBe('notebook');
  652. });
  653. it('should handle a python file', () => {
  654. const ft = registry.getFileTypesForPath('foo/bar/baz.py');
  655. expect(ft[0].name).toBe('python');
  656. });
  657. it('should return an empty list for an unknown file', () => {
  658. const ft = registry.getFileTypesForPath('foo/bar/baz.weird');
  659. expect(ft.length).toBe(0);
  660. });
  661. it('should get the most specific extension first', () => {
  662. [
  663. { name: 'json', extensions: ['.json'] },
  664. { name: 'vega', extensions: ['.vg.json'] }
  665. ].forEach(ft => {
  666. registry.addFileType(ft);
  667. });
  668. const ft = registry.getFileTypesForPath('foo/bar/baz.vg.json');
  669. expect(ft[0].name).toBe('vega');
  670. expect(ft[1].name).toBe('json');
  671. });
  672. it.each([
  673. ['python', null, 'foo/bar/baz.PY'],
  674. ['r-markdown', ['.Rmd'], 'foo/bar/baz.Rmd']
  675. ])('should be case insensitive', (name, extensions, filename) => {
  676. if (extensions) {
  677. registry.addFileType({ name, extensions });
  678. }
  679. const ft = registry.getFileTypesForPath(filename);
  680. expect(ft[0].name).toBe(name);
  681. });
  682. it('should support pattern matching', () => {
  683. registry.addFileType({
  684. name: 'test',
  685. extensions: ['.temp'],
  686. pattern: '.*\\.test$'
  687. });
  688. const ft = registry.getFileTypesForPath('foo/bar/baz.test');
  689. expect(ft[0].name).toBe('test');
  690. const ft2 = registry.getFileTypesForPath('foo/bar/baz.temp');
  691. expect(ft2[0].name).toBe('test');
  692. });
  693. it('should returns all file types', () => {
  694. registry.addFileType({
  695. name: 'test',
  696. extensions: ['.foo.bar']
  697. });
  698. const ft = registry.getFileTypesForPath('foo/bar/test.foo.bar');
  699. expect(ft.length).toBeGreaterThanOrEqual(2);
  700. expect(ft.map(f => f.name)).toContain('test');
  701. });
  702. });
  703. });
  704. });