undoablelist.spec.ts 7.1 KB

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