openfiledialog.spec.ts 8.9 KB

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