registry.spec.ts 22 KB

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