undoablelist.spec.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import 'jest';
  4. import { JSONObject } from '@lumino/coreutils';
  5. import { ObservableUndoableList, ISerializer } from '@jupyterlab/observables';
  6. class Test {
  7. constructor(value: JSONObject) {
  8. this._value = value;
  9. }
  10. get value(): JSONObject {
  11. return this._value;
  12. }
  13. private _value: JSONObject;
  14. }
  15. let count = 0;
  16. class Serializer implements ISerializer<Test> {
  17. fromJSON(value: JSONObject): Test {
  18. value['count'] = count++;
  19. return new Test(value);
  20. }
  21. toJSON(value: Test): JSONObject {
  22. return value.value;
  23. }
  24. }
  25. const serializer = new Serializer();
  26. const value: JSONObject = { name: 'foo' };
  27. describe('@jupyterlab/observables', () => {
  28. describe('ObservableUndoableList', () => {
  29. describe('#constructor', () => {
  30. it('should create a new ObservableUndoableList', () => {
  31. const list = new ObservableUndoableList(serializer);
  32. expect(list).toBeInstanceOf(ObservableUndoableList);
  33. });
  34. });
  35. describe('#canRedo', () => {
  36. it('should return false if there is no history', () => {
  37. const list = new ObservableUndoableList(serializer);
  38. expect(list.canRedo).toBe(false);
  39. });
  40. it('should return true if there is an undo that can be redone', () => {
  41. const list = new ObservableUndoableList(serializer);
  42. list.push(new Test(value));
  43. list.undo();
  44. expect(list.canRedo).toBe(true);
  45. });
  46. });
  47. describe('#canUndo', () => {
  48. it('should return false if there is no history', () => {
  49. const list = new ObservableUndoableList(serializer);
  50. expect(list.canUndo).toBe(false);
  51. });
  52. it('should return true if there is a change that can be undone', () => {
  53. const list = new ObservableUndoableList(serializer);
  54. list.push(serializer.fromJSON(value));
  55. expect(list.canUndo).toBe(true);
  56. });
  57. });
  58. describe('#dispose()', () => {
  59. it('should dispose of the resources used by the list', () => {
  60. const list = new ObservableUndoableList(serializer);
  61. list.dispose();
  62. expect(list.isDisposed).toBe(true);
  63. list.dispose();
  64. expect(list.isDisposed).toBe(true);
  65. });
  66. });
  67. describe('#beginCompoundOperation()', () => {
  68. it('should begin a compound operation', () => {
  69. const list = new ObservableUndoableList(serializer);
  70. list.beginCompoundOperation();
  71. list.push(serializer.fromJSON(value));
  72. list.push(serializer.fromJSON(value));
  73. list.endCompoundOperation();
  74. expect(list.canUndo).toBe(true);
  75. list.undo();
  76. expect(list.canUndo).toBe(false);
  77. });
  78. it('should not be undoable if isUndoAble is set to false', () => {
  79. const list = new ObservableUndoableList(serializer);
  80. list.beginCompoundOperation(false);
  81. list.push(serializer.fromJSON(value));
  82. list.push(serializer.fromJSON(value));
  83. list.endCompoundOperation();
  84. expect(list.canUndo).toBe(false);
  85. });
  86. });
  87. describe('#endCompoundOperation()', () => {
  88. it('should end a compound operation', () => {
  89. const list = new ObservableUndoableList(serializer);
  90. list.beginCompoundOperation();
  91. list.push(serializer.fromJSON(value));
  92. list.push(serializer.fromJSON(value));
  93. list.endCompoundOperation();
  94. expect(list.canUndo).toBe(true);
  95. list.undo();
  96. expect(list.canUndo).toBe(false);
  97. });
  98. });
  99. describe('#undo()', () => {
  100. it('should undo a push', () => {
  101. const list = new ObservableUndoableList(serializer);
  102. list.push(serializer.fromJSON(value));
  103. list.undo();
  104. expect(list.length).toBe(0);
  105. });
  106. it('should undo a pushAll', () => {
  107. const list = new ObservableUndoableList(serializer);
  108. list.pushAll([serializer.fromJSON(value), serializer.fromJSON(value)]);
  109. list.undo();
  110. expect(list.length).toBe(0);
  111. });
  112. it('should undo a remove', () => {
  113. const list = new ObservableUndoableList(serializer);
  114. list.pushAll([serializer.fromJSON(value), serializer.fromJSON(value)]);
  115. list.remove(0);
  116. list.undo();
  117. expect(list.length).toBe(2);
  118. });
  119. it('should undo a removeRange', () => {
  120. const list = new ObservableUndoableList(serializer);
  121. list.pushAll([
  122. serializer.fromJSON(value),
  123. serializer.fromJSON(value),
  124. serializer.fromJSON(value),
  125. serializer.fromJSON(value),
  126. serializer.fromJSON(value),
  127. serializer.fromJSON(value)
  128. ]);
  129. list.removeRange(1, 3);
  130. list.undo();
  131. expect(list.length).toBe(6);
  132. });
  133. it('should undo a move', () => {
  134. const items = [
  135. serializer.fromJSON(value),
  136. serializer.fromJSON(value),
  137. serializer.fromJSON(value)
  138. ];
  139. const list = new ObservableUndoableList(serializer);
  140. list.pushAll(items);
  141. list.move(1, 2);
  142. list.undo();
  143. expect((list.get(1) as any)['count']).toBe((items[1] as any)['count']);
  144. });
  145. });
  146. describe('#redo()', () => {
  147. it('should redo a push', () => {
  148. const list = new ObservableUndoableList(serializer);
  149. list.push(serializer.fromJSON(value));
  150. list.undo();
  151. list.redo();
  152. expect(list.length).toBe(1);
  153. });
  154. it('should redo a pushAll', () => {
  155. const list = new ObservableUndoableList(serializer);
  156. list.pushAll([serializer.fromJSON(value), serializer.fromJSON(value)]);
  157. list.undo();
  158. list.redo();
  159. expect(list.length).toBe(2);
  160. });
  161. it('should redo a remove', () => {
  162. const list = new ObservableUndoableList(serializer);
  163. list.pushAll([serializer.fromJSON(value), serializer.fromJSON(value)]);
  164. list.remove(0);
  165. list.undo();
  166. list.redo();
  167. expect(list.length).toBe(1);
  168. });
  169. it('should redo a removeRange', () => {
  170. const list = new ObservableUndoableList(serializer);
  171. list.pushAll([
  172. serializer.fromJSON(value),
  173. serializer.fromJSON(value),
  174. serializer.fromJSON(value),
  175. serializer.fromJSON(value),
  176. serializer.fromJSON(value),
  177. serializer.fromJSON(value)
  178. ]);
  179. list.removeRange(1, 3);
  180. list.undo();
  181. list.redo();
  182. expect(list.length).toBe(4);
  183. });
  184. it('should undo a move', () => {
  185. const items = [
  186. serializer.fromJSON(value),
  187. serializer.fromJSON(value),
  188. serializer.fromJSON(value)
  189. ];
  190. const list = new ObservableUndoableList(serializer);
  191. list.pushAll(items);
  192. list.move(1, 2);
  193. list.undo();
  194. list.redo();
  195. expect((list.get(2) as any)['count']).toBe((items[1] as any)['count']);
  196. });
  197. });
  198. describe('#clearUndo()', () => {
  199. it('should clear the undo stack', () => {
  200. const list = new ObservableUndoableList(serializer);
  201. list.push(serializer.fromJSON(value));
  202. list.clearUndo();
  203. expect(list.canUndo).toBe(false);
  204. });
  205. });
  206. });
  207. });