crumbs.spec.ts 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import 'jest';
  4. import expect from 'expect';
  5. // Copyright (c) Jupyter Development Team.
  6. // Distributed under the terms of the Modified BSD License.
  7. import { DocumentManager, IDocumentManager } from '@jupyterlab/docmanager';
  8. import { DocumentRegistry, TextModelFactory } from '@jupyterlab/docregistry';
  9. import { BreadCrumbs, FileBrowserModel } from '../src';
  10. import { ServiceManager } from '@jupyterlab/services';
  11. import { framePromise, signalToPromise } from '@jupyterlab/testutils';
  12. import * as Mock from '@jupyterlab/testutils/lib/mock';
  13. import { Message, MessageLoop } from '@lumino/messaging';
  14. import { Widget } from '@lumino/widgets';
  15. import { simulate } from 'simulate-event';
  16. const HOME_ITEM_CLASS = 'jp-BreadCrumbs-home';
  17. const ITEM_CLASS = 'jp-BreadCrumbs-item';
  18. const ITEM_QUERY = `.${HOME_ITEM_CLASS}, .${ITEM_CLASS}`;
  19. class LogCrumbs extends BreadCrumbs {
  20. methods: string[] = [];
  21. events: string[] = [];
  22. handleEvent(event: Event): void {
  23. super.handleEvent(event);
  24. this.events.push(event.type);
  25. }
  26. protected onAfterAttach(msg: Message): void {
  27. super.onAfterAttach(msg);
  28. this.methods.push('onAfterAttach');
  29. }
  30. protected onBeforeDetach(msg: Message): void {
  31. super.onBeforeDetach(msg);
  32. this.methods.push('onBeforeDetach');
  33. }
  34. protected onUpdateRequest(msg: Message): void {
  35. super.onUpdateRequest(msg);
  36. this.methods.push('onUpdateRequest');
  37. }
  38. }
  39. describe('filebrowser/model', () => {
  40. let manager: IDocumentManager;
  41. let serviceManager: ServiceManager.IManager;
  42. let registry: DocumentRegistry;
  43. let model: FileBrowserModel;
  44. let crumbs: LogCrumbs;
  45. let first: string;
  46. let second: string;
  47. let third: string;
  48. let path: string;
  49. beforeAll(async () => {
  50. const opener: DocumentManager.IWidgetOpener = {
  51. open: widget => {
  52. /* no op */
  53. }
  54. };
  55. registry = new DocumentRegistry({
  56. textModelFactory: new TextModelFactory()
  57. });
  58. serviceManager = new Mock.ServiceManagerMock();
  59. manager = new DocumentManager({
  60. registry,
  61. opener,
  62. manager: serviceManager
  63. });
  64. const contents = serviceManager.contents;
  65. let cModel = await contents.newUntitled({ type: 'directory' });
  66. first = cModel.name;
  67. cModel = await contents.newUntitled({
  68. path: cModel.path,
  69. type: 'directory'
  70. });
  71. second = cModel.name;
  72. cModel = await contents.newUntitled({
  73. path: cModel.path,
  74. type: 'directory'
  75. });
  76. third = cModel.name;
  77. path = cModel.path;
  78. });
  79. beforeEach(async () => {
  80. model = new FileBrowserModel({ manager });
  81. await model.cd(path);
  82. crumbs = new LogCrumbs({ model });
  83. });
  84. afterEach(() => {
  85. model.dispose();
  86. });
  87. describe('BreadCrumbs', () => {
  88. describe('#constructor()', () => {
  89. it('should create a new BreadCrumbs instance', () => {
  90. const bread = new BreadCrumbs({ model });
  91. expect(bread).toBeInstanceOf(BreadCrumbs);
  92. const items = crumbs.node.querySelectorAll(ITEM_QUERY);
  93. expect(items.length).toBe(1);
  94. });
  95. it('should add the jp-BreadCrumbs class', () => {
  96. expect(crumbs.hasClass('jp-BreadCrumbs')).toBe(true);
  97. });
  98. });
  99. describe('#handleEvent()', () => {
  100. describe('click', () => {
  101. it('should switch to the parent directory', async () => {
  102. Widget.attach(crumbs, document.body);
  103. MessageLoop.sendMessage(crumbs, Widget.Msg.UpdateRequest);
  104. let items = crumbs.node.querySelectorAll(ITEM_QUERY);
  105. expect(items.length).toBe(4);
  106. const promise = signalToPromise(model.pathChanged);
  107. expect(items[2].textContent).toBe(second);
  108. simulate(items[2], 'click');
  109. await promise;
  110. MessageLoop.sendMessage(crumbs, Widget.Msg.UpdateRequest);
  111. items = crumbs.node.querySelectorAll(ITEM_QUERY);
  112. expect(items.length).toBe(3);
  113. });
  114. it('should switch to the home directory', async () => {
  115. Widget.attach(crumbs, document.body);
  116. MessageLoop.sendMessage(crumbs, Widget.Msg.UpdateRequest);
  117. let items = crumbs.node.querySelectorAll(ITEM_QUERY);
  118. const promise = signalToPromise(model.pathChanged);
  119. simulate(items[0], 'click');
  120. await promise;
  121. MessageLoop.sendMessage(crumbs, Widget.Msg.UpdateRequest);
  122. items = crumbs.node.querySelectorAll(ITEM_QUERY);
  123. expect(items.length).toBe(1);
  124. expect(model.path).toBe('');
  125. });
  126. it('should switch to the grandparent directory', async () => {
  127. Widget.attach(crumbs, document.body);
  128. MessageLoop.sendMessage(crumbs, Widget.Msg.UpdateRequest);
  129. let items = crumbs.node.querySelectorAll(ITEM_QUERY);
  130. const promise = signalToPromise(model.pathChanged);
  131. simulate(items[1], 'click');
  132. await promise;
  133. MessageLoop.sendMessage(crumbs, Widget.Msg.UpdateRequest);
  134. items = crumbs.node.querySelectorAll(ITEM_QUERY);
  135. expect(items.length).toBe(2);
  136. expect(model.path).toBe(first);
  137. });
  138. it('should refresh the current directory', async () => {
  139. Widget.attach(crumbs, document.body);
  140. MessageLoop.sendMessage(crumbs, Widget.Msg.UpdateRequest);
  141. let items = crumbs.node.querySelectorAll(ITEM_QUERY);
  142. const promise = signalToPromise(model.refreshed);
  143. expect(items[3].textContent).toBe(third);
  144. simulate(items[3], 'click');
  145. await promise;
  146. MessageLoop.sendMessage(crumbs, Widget.Msg.UpdateRequest);
  147. items = crumbs.node.querySelectorAll(ITEM_QUERY);
  148. expect(items.length).toBe(4);
  149. expect(model.path).toBe(path);
  150. });
  151. });
  152. });
  153. describe('#onAfterAttach()', () => {
  154. it('should post an update request', async () => {
  155. Widget.attach(crumbs, document.body);
  156. expect(crumbs.methods).toEqual(
  157. expect.arrayContaining(['onAfterAttach'])
  158. );
  159. await framePromise();
  160. expect(crumbs.methods).toEqual(
  161. expect.arrayContaining(['onUpdateRequest'])
  162. );
  163. });
  164. it('should add event listeners', () => {
  165. Widget.attach(crumbs, document.body);
  166. simulate(crumbs.node, 'click');
  167. expect(crumbs.events).toEqual(expect.arrayContaining(['click']));
  168. });
  169. });
  170. describe('#onBeforeDetach()', () => {
  171. it('should remove event listeners', () => {
  172. Widget.attach(crumbs, document.body);
  173. Widget.detach(crumbs);
  174. simulate(crumbs.node, 'click');
  175. expect(crumbs.events).not.toEqual(expect.arrayContaining(['click']));
  176. });
  177. });
  178. describe('#onUpdateRequest()', () => {
  179. it('should be called when the model updates', async () => {
  180. const model = new FileBrowserModel({ manager });
  181. await model.cd(path);
  182. crumbs = new LogCrumbs({ model });
  183. await model.cd('..');
  184. await framePromise();
  185. expect(crumbs.methods).toEqual(
  186. expect.arrayContaining(['onUpdateRequest'])
  187. );
  188. const items = crumbs.node.querySelectorAll(ITEM_QUERY);
  189. expect(items.length).toBe(3);
  190. model.dispose();
  191. });
  192. });
  193. });
  194. });