layoutrestorer.spec.ts 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import { ILabShell, LayoutRestorer } from '@jupyterlab/application';
  4. import { WidgetTracker } from '@jupyterlab/apputils';
  5. import { StateDB } from '@jupyterlab/statedb';
  6. import { CommandRegistry } from '@lumino/commands';
  7. import { PromiseDelegate } from '@lumino/coreutils';
  8. import { Widget } from '@lumino/widgets';
  9. describe('apputils', () => {
  10. describe('LayoutRestorer', () => {
  11. describe('#constructor()', () => {
  12. it('should construct a new layout restorer', () => {
  13. const restorer = new LayoutRestorer({
  14. connector: new StateDB(),
  15. first: Promise.resolve<void>(void 0),
  16. registry: new CommandRegistry()
  17. });
  18. expect(restorer).toBeInstanceOf(LayoutRestorer);
  19. });
  20. });
  21. describe('#restored', () => {
  22. it('should be a promise available right away', () => {
  23. const restorer = new LayoutRestorer({
  24. connector: new StateDB(),
  25. first: Promise.resolve<void>(void 0),
  26. registry: new CommandRegistry()
  27. });
  28. expect(restorer.restored).toBeInstanceOf(Promise);
  29. });
  30. it('should resolve when restorer is done', async () => {
  31. const ready = new PromiseDelegate<void>();
  32. const restorer = new LayoutRestorer({
  33. connector: new StateDB(),
  34. first: ready.promise,
  35. registry: new CommandRegistry()
  36. });
  37. const promise = restorer.restored;
  38. ready.resolve(void 0);
  39. await promise;
  40. });
  41. });
  42. describe('#add()', () => {
  43. it('should add a widget in the main area to be tracked by the restorer', async () => {
  44. const ready = new PromiseDelegate<void>();
  45. const restorer = new LayoutRestorer({
  46. connector: new StateDB(),
  47. first: ready.promise,
  48. registry: new CommandRegistry()
  49. });
  50. const currentWidget = new Widget();
  51. const dehydrated: ILabShell.ILayout = {
  52. mainArea: { currentWidget, dock: null },
  53. downArea: { currentWidget: null, widgets: null, size: null },
  54. leftArea: { collapsed: true, currentWidget: null, widgets: null },
  55. rightArea: { collapsed: true, currentWidget: null, widgets: null },
  56. relativeSizes: null
  57. };
  58. restorer.add(currentWidget, 'test-one');
  59. ready.resolve(void 0);
  60. await restorer.restored;
  61. await restorer.save(dehydrated);
  62. const layout = await restorer.fetch();
  63. expect(layout.mainArea?.currentWidget).toBe(currentWidget);
  64. });
  65. it('should add a widget in the down area to be tracked by the restorer', async () => {
  66. const ready = new PromiseDelegate<void>();
  67. const restorer = new LayoutRestorer({
  68. connector: new StateDB(),
  69. first: ready.promise,
  70. registry: new CommandRegistry()
  71. });
  72. const currentWidget = new Widget();
  73. const dehydrated: ILabShell.ILayout = {
  74. mainArea: { currentWidget: null, dock: null },
  75. downArea: { currentWidget, widgets: null, size: null },
  76. leftArea: { collapsed: true, currentWidget: null, widgets: null },
  77. rightArea: { collapsed: true, currentWidget: null, widgets: null },
  78. relativeSizes: null
  79. };
  80. restorer.add(currentWidget, 'test-one');
  81. ready.resolve(void 0);
  82. await restorer.restored;
  83. await restorer.save(dehydrated);
  84. const layout = await restorer.fetch();
  85. expect(layout.downArea?.currentWidget).toBe(currentWidget);
  86. });
  87. });
  88. describe('#fetch()', () => {
  89. it('should always return a value', async () => {
  90. const restorer = new LayoutRestorer({
  91. connector: new StateDB(),
  92. first: Promise.resolve(void 0),
  93. registry: new CommandRegistry()
  94. });
  95. const layout = await restorer.fetch();
  96. expect(layout).not.toBe(null);
  97. });
  98. it('should fetch saved data', async () => {
  99. const ready = new PromiseDelegate<void>();
  100. const restorer = new LayoutRestorer({
  101. connector: new StateDB(),
  102. first: ready.promise,
  103. registry: new CommandRegistry()
  104. });
  105. const currentWidget = new Widget();
  106. // The `fresh` attribute is only here to check against the return value.
  107. const dehydrated: ILabShell.ILayout = {
  108. fresh: false,
  109. mainArea: { currentWidget: null, dock: null },
  110. downArea: { currentWidget: null, widgets: null, size: 0 },
  111. leftArea: {
  112. currentWidget,
  113. collapsed: true,
  114. widgets: [currentWidget]
  115. },
  116. rightArea: { collapsed: true, currentWidget: null, widgets: null },
  117. relativeSizes: null
  118. };
  119. restorer.add(currentWidget, 'test-one');
  120. ready.resolve(void 0);
  121. await restorer.restored;
  122. await restorer.save(dehydrated);
  123. const layout = await restorer.fetch();
  124. expect(layout).toEqual(dehydrated);
  125. });
  126. });
  127. describe('#restore()', () => {
  128. it('should restore the widgets in a tracker', async () => {
  129. const tracker = new WidgetTracker({ namespace: 'foo-widget' });
  130. const registry = new CommandRegistry();
  131. const state = new StateDB();
  132. const ready = new PromiseDelegate<void>();
  133. const restorer = new LayoutRestorer({
  134. connector: state,
  135. first: ready.promise,
  136. registry
  137. });
  138. let called = false;
  139. const key = `${tracker.namespace}:${tracker.namespace}`;
  140. registry.addCommand(tracker.namespace, {
  141. execute: () => {
  142. called = true;
  143. }
  144. });
  145. await state.save(key, { data: null });
  146. ready.resolve(undefined);
  147. await restorer.restore(tracker, {
  148. name: () => tracker.namespace,
  149. command: tracker.namespace
  150. });
  151. await restorer.restored;
  152. expect(called).toBe(true);
  153. });
  154. });
  155. describe('#save()', () => {
  156. it('should not run before `first` promise', async () => {
  157. const restorer = new LayoutRestorer({
  158. connector: new StateDB(),
  159. first: new Promise(() => {
  160. // no op
  161. }),
  162. registry: new CommandRegistry()
  163. });
  164. const dehydrated: ILabShell.ILayout = {
  165. mainArea: { currentWidget: null, dock: null },
  166. downArea: { currentWidget: null, widgets: null, size: null },
  167. leftArea: { currentWidget: null, collapsed: true, widgets: null },
  168. rightArea: { collapsed: true, currentWidget: null, widgets: null },
  169. relativeSizes: null
  170. };
  171. await expect(restorer.save(dehydrated)).rejects.toBe(
  172. 'save() was called prematurely.'
  173. );
  174. });
  175. it('should save data', async () => {
  176. const ready = new PromiseDelegate<void>();
  177. const restorer = new LayoutRestorer({
  178. connector: new StateDB(),
  179. first: ready.promise,
  180. registry: new CommandRegistry()
  181. });
  182. const currentWidget = new Widget();
  183. // The `fresh` attribute is only here to check against the return value.
  184. const dehydrated: ILabShell.ILayout = {
  185. fresh: false,
  186. mainArea: { currentWidget: null, dock: null },
  187. downArea: { currentWidget: null, widgets: null, size: 0 },
  188. leftArea: {
  189. currentWidget,
  190. collapsed: true,
  191. widgets: [currentWidget]
  192. },
  193. rightArea: { collapsed: true, currentWidget: null, widgets: null },
  194. relativeSizes: null
  195. };
  196. restorer.add(currentWidget, 'test-one');
  197. ready.resolve(void 0);
  198. await restorer.restored;
  199. await restorer.save(dehydrated);
  200. const layout = await restorer.fetch();
  201. expect(layout).toEqual(dehydrated);
  202. });
  203. });
  204. });
  205. });