layoutrestorer.spec.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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 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. leftArea: { collapsed: true, currentWidget: null, widgets: null },
  54. rightArea: { collapsed: true, currentWidget: null, widgets: null },
  55. relativeSizes: null
  56. };
  57. restorer.add(currentWidget, 'test-one');
  58. ready.resolve(void 0);
  59. await restorer.restored;
  60. await restorer.save(dehydrated);
  61. const layout = await restorer.fetch();
  62. expect(layout.mainArea?.currentWidget).toBe(currentWidget);
  63. });
  64. });
  65. describe('#fetch()', () => {
  66. it('should always return a value', async () => {
  67. const restorer = new LayoutRestorer({
  68. connector: new StateDB(),
  69. first: Promise.resolve(void 0),
  70. registry: new CommandRegistry()
  71. });
  72. const layout = await restorer.fetch();
  73. expect(layout).not.toBe(null);
  74. });
  75. it('should fetch saved data', async () => {
  76. const ready = new PromiseDelegate<void>();
  77. const restorer = new LayoutRestorer({
  78. connector: new StateDB(),
  79. first: ready.promise,
  80. registry: new CommandRegistry()
  81. });
  82. const currentWidget = new Widget();
  83. // The `fresh` attribute is only here to check against the return value.
  84. const dehydrated: ILabShell.ILayout = {
  85. fresh: false,
  86. mainArea: { currentWidget: null, dock: null },
  87. leftArea: {
  88. currentWidget,
  89. collapsed: true,
  90. widgets: [currentWidget]
  91. },
  92. rightArea: { collapsed: true, currentWidget: null, widgets: null },
  93. relativeSizes: null
  94. };
  95. restorer.add(currentWidget, 'test-one');
  96. ready.resolve(void 0);
  97. await restorer.restored;
  98. await restorer.save(dehydrated);
  99. const layout = await restorer.fetch();
  100. expect(layout).toEqual(dehydrated);
  101. });
  102. });
  103. describe('#restore()', () => {
  104. it('should restore the widgets in a tracker', async () => {
  105. const tracker = new WidgetTracker({ namespace: 'foo-widget' });
  106. const registry = new CommandRegistry();
  107. const state = new StateDB();
  108. const ready = new PromiseDelegate<void>();
  109. const restorer = new LayoutRestorer({
  110. connector: state,
  111. first: ready.promise,
  112. registry
  113. });
  114. let called = false;
  115. const key = `${tracker.namespace}:${tracker.namespace}`;
  116. registry.addCommand(tracker.namespace, {
  117. execute: () => {
  118. called = true;
  119. }
  120. });
  121. await state.save(key, { data: null });
  122. ready.resolve(undefined);
  123. await restorer.restore(tracker, {
  124. name: () => tracker.namespace,
  125. command: tracker.namespace
  126. });
  127. await restorer.restored;
  128. expect(called).toBe(true);
  129. });
  130. });
  131. describe('#save()', () => {
  132. it('should not run before `first` promise', async () => {
  133. const restorer = new LayoutRestorer({
  134. connector: new StateDB(),
  135. first: new Promise(() => {
  136. // no op
  137. }),
  138. registry: new CommandRegistry()
  139. });
  140. const dehydrated: ILabShell.ILayout = {
  141. mainArea: { currentWidget: null, dock: null },
  142. leftArea: { currentWidget: null, collapsed: true, widgets: null },
  143. rightArea: { collapsed: true, currentWidget: null, widgets: null },
  144. relativeSizes: null
  145. };
  146. await expect(restorer.save(dehydrated)).rejects.toBe(
  147. 'save() was called prematurely.'
  148. );
  149. });
  150. it('should save data', async () => {
  151. const ready = new PromiseDelegate<void>();
  152. const restorer = new LayoutRestorer({
  153. connector: new StateDB(),
  154. first: ready.promise,
  155. registry: new CommandRegistry()
  156. });
  157. const currentWidget = new Widget();
  158. // The `fresh` attribute is only here to check against the return value.
  159. const dehydrated: ILabShell.ILayout = {
  160. fresh: false,
  161. mainArea: { currentWidget: null, dock: null },
  162. leftArea: {
  163. currentWidget,
  164. collapsed: true,
  165. widgets: [currentWidget]
  166. },
  167. rightArea: { collapsed: true, currentWidget: null, widgets: null },
  168. relativeSizes: null
  169. };
  170. restorer.add(currentWidget, 'test-one');
  171. ready.resolve(void 0);
  172. await restorer.restored;
  173. await restorer.save(dehydrated);
  174. const layout = await restorer.fetch();
  175. expect(layout).toEqual(dehydrated);
  176. });
  177. });
  178. });
  179. });