openfiledialog.spec.ts 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import expect from 'expect';
  4. import { toArray } from '@lumino/algorithm';
  5. import { DocumentManager, IDocumentManager } from '@jupyterlab/docmanager';
  6. import { DocumentRegistry, TextModelFactory } from '@jupyterlab/docregistry';
  7. import { FileDialog, FilterFileBrowserModel, FileBrowserModel } from '../src';
  8. import { ServiceManager, Contents } from '@jupyterlab/services';
  9. import {
  10. acceptDialog,
  11. dismissDialog,
  12. waitForDialog,
  13. sleep,
  14. framePromise
  15. } from '@jupyterlab/testutils';
  16. import * as Mock from '@jupyterlab/testutils/lib/mock';
  17. import { simulate } from 'simulate-event';
  18. describe('@jupyterlab/filebrowser', () => {
  19. let manager: IDocumentManager;
  20. let serviceManager: ServiceManager.IManager;
  21. let registry: DocumentRegistry;
  22. beforeAll(async () => {
  23. const opener: DocumentManager.IWidgetOpener = {
  24. open: widget => {
  25. /* no op */
  26. }
  27. };
  28. registry = new DocumentRegistry({
  29. textModelFactory: new TextModelFactory()
  30. });
  31. serviceManager = new Mock.ServiceManagerMock();
  32. manager = new DocumentManager({
  33. registry,
  34. opener,
  35. manager: serviceManager
  36. });
  37. const contents = serviceManager.contents;
  38. await contents.newUntitled({ type: 'directory' });
  39. await contents.newUntitled({ type: 'file' });
  40. await contents.newUntitled({ type: 'notebook' });
  41. });
  42. describe('FilterFileBrowserModel', () => {
  43. describe('#constructor()', () => {
  44. it('should construct a new filtered file browser model', () => {
  45. const model = new FilterFileBrowserModel({ manager });
  46. expect(model).toBeInstanceOf(FilterFileBrowserModel);
  47. });
  48. it('should accept filter option', () => {
  49. const model = new FilterFileBrowserModel({
  50. manager,
  51. filter: (model: Contents.IModel) => false
  52. });
  53. expect(model).toBeInstanceOf(FilterFileBrowserModel);
  54. });
  55. });
  56. describe('#items()', () => {
  57. it('should list all elements if no filter is defined', async () => {
  58. const filteredModel = new FilterFileBrowserModel({
  59. manager
  60. });
  61. await filteredModel.cd();
  62. const model = new FileBrowserModel({ manager });
  63. await model.cd();
  64. const filteredItems = toArray(filteredModel.items());
  65. const items = toArray(model.items());
  66. expect(filteredItems.length).toBe(items.length);
  67. });
  68. it('should list all directories whatever the filter', async () => {
  69. const filteredModel = new FilterFileBrowserModel({
  70. manager,
  71. filter: (model: Contents.IModel) => false
  72. });
  73. await filteredModel.cd();
  74. const model = new FileBrowserModel({ manager });
  75. await model.cd();
  76. const filteredItems = toArray(filteredModel.items());
  77. const items = toArray(model.items());
  78. const folders = items.filter(item => item.type === 'directory');
  79. expect(filteredItems.length).toBe(folders.length);
  80. });
  81. it('should respect the filter', async () => {
  82. const filteredModel = new FilterFileBrowserModel({
  83. manager,
  84. filter: (model: Contents.IModel) => model.type === 'notebook'
  85. });
  86. await filteredModel.cd();
  87. const model = new FileBrowserModel({ manager });
  88. await model.cd();
  89. const filteredItems = toArray(
  90. filteredModel.items()
  91. ) as Contents.IModel[];
  92. const items = toArray(model.items());
  93. const shownItems = items.filter(
  94. item => item.type === 'directory' || item.type === 'notebook'
  95. );
  96. expect(filteredItems.length).toBe(shownItems.length);
  97. const notebooks = filteredItems.filter(
  98. item => item.type === 'notebook'
  99. );
  100. expect(notebooks.length).toBeGreaterThan(0);
  101. });
  102. });
  103. });
  104. describe('FileDialog.getOpenFiles()', () => {
  105. it('should create a dialog', async () => {
  106. const dialog = FileDialog.getOpenFiles({
  107. manager
  108. });
  109. await dismissDialog();
  110. const result = await dialog;
  111. expect(result.button.accept).toBe(false);
  112. expect(result.value).toBeNull();
  113. });
  114. it('should accept options', async () => {
  115. const node = document.createElement('div');
  116. document.body.appendChild(node);
  117. const dialog = FileDialog.getOpenFiles({
  118. manager,
  119. title: 'Select a notebook',
  120. host: node,
  121. filter: (value: Contents.IModel) => value.type === 'notebook'
  122. });
  123. await acceptDialog();
  124. const result = await dialog;
  125. expect(result.button.accept).toBe(true);
  126. const items = result.value!;
  127. expect(items.length).toBe(1);
  128. document.body.removeChild(node);
  129. });
  130. it('should return one selected file', async () => {
  131. const node = document.createElement('div');
  132. document.body.appendChild(node);
  133. const dialog = FileDialog.getOpenFiles({
  134. manager,
  135. title: 'Select a notebook',
  136. host: node,
  137. filter: (value: Contents.IModel) => value.type === 'notebook'
  138. });
  139. await waitForDialog();
  140. await framePromise();
  141. let counter = 0;
  142. const listing = node.getElementsByClassName('jp-DirListing-content')[0];
  143. expect(listing).toBeTruthy();
  144. let items = listing.getElementsByTagName('li');
  145. counter = 0;
  146. // Wait for the directory listing to be populated
  147. while (items.length === 0 && counter < 100) {
  148. await sleep(10);
  149. items = listing.getElementsByTagName('li');
  150. counter++;
  151. }
  152. // Fails if there is no items shown
  153. expect(items.length).toBeGreaterThan(0);
  154. // Emulate notebook file selection
  155. const item = listing.querySelector('li[data-file-type="notebook"]')!;
  156. simulate(item, 'mousedown');
  157. await acceptDialog();
  158. const result = await dialog;
  159. const files = result.value!;
  160. expect(files.length).toBe(1);
  161. expect(files[0].type).toBe('notebook');
  162. expect(files[0].name).toEqual(expect.stringMatching(/Untitled.*.ipynb/));
  163. document.body.removeChild(node);
  164. });
  165. it('should return current path if nothing is selected', async () => {
  166. const dialog = FileDialog.getOpenFiles({
  167. manager
  168. });
  169. await acceptDialog();
  170. const result = await dialog;
  171. const items = result.value!;
  172. expect(items.length).toBe(1);
  173. expect(items[0].type).toBe('directory');
  174. expect(items[0].path).toBe('');
  175. });
  176. });
  177. describe('FileDialog.getExistingDirectory()', () => {
  178. it('should create a dialog', async () => {
  179. const dialog = FileDialog.getExistingDirectory({
  180. manager
  181. });
  182. await dismissDialog();
  183. const result = await dialog;
  184. expect(result.button.accept).toBe(false);
  185. expect(result.value).toBeNull();
  186. });
  187. it('should accept options', async () => {
  188. const node = document.createElement('div');
  189. document.body.appendChild(node);
  190. const dialog = FileDialog.getExistingDirectory({
  191. manager,
  192. title: 'Select a folder',
  193. host: node
  194. });
  195. await acceptDialog();
  196. const result = await dialog;
  197. expect(result.button.accept).toBe(true);
  198. expect(result.value!.length).toBe(1);
  199. document.body.removeChild(node);
  200. });
  201. it('should return one selected directory', async () => {
  202. const node = document.createElement('div');
  203. document.body.appendChild(node);
  204. const dialog = FileDialog.getExistingDirectory({
  205. manager,
  206. title: 'Select a folder',
  207. host: node
  208. });
  209. await waitForDialog();
  210. await framePromise();
  211. let counter = 0;
  212. const listing = node.getElementsByClassName('jp-DirListing-content')[0];
  213. expect(listing).toBeTruthy();
  214. let items = listing.getElementsByTagName('li');
  215. // Wait for the directory listing to be populated
  216. while (items.length === 0 && counter < 100) {
  217. await sleep(10);
  218. items = listing.getElementsByTagName('li');
  219. counter++;
  220. }
  221. // Fails if there is no items shown
  222. expect(items.length).toBeGreaterThan(0);
  223. // Emulate notebook file selection
  224. simulate(items.item(items.length - 1)!, 'mousedown');
  225. await acceptDialog();
  226. const result = await dialog;
  227. const files = result.value!;
  228. expect(files.length).toBe(1);
  229. expect(files[0].type).toBe('directory');
  230. expect(files[0].name).toEqual(
  231. expect.stringMatching(/Untitled Folder( \d+)?/)
  232. );
  233. document.body.removeChild(node);
  234. });
  235. it('should return current path if nothing is selected', async () => {
  236. const dialog = FileDialog.getExistingDirectory({
  237. manager
  238. });
  239. await acceptDialog();
  240. const result = await dialog;
  241. const items = result.value!;
  242. expect(items.length).toBe(1);
  243. expect(items[0].type).toBe('directory');
  244. expect(items[0].path).toBe('');
  245. });
  246. });
  247. });