summaryrefslogtreecommitdiff
path: root/spec/frontend/lib/utils/undo_stack_spec.js
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/lib/utils/undo_stack_spec.js')
-rw-r--r--spec/frontend/lib/utils/undo_stack_spec.js237
1 files changed, 0 insertions, 237 deletions
diff --git a/spec/frontend/lib/utils/undo_stack_spec.js b/spec/frontend/lib/utils/undo_stack_spec.js
deleted file mode 100644
index 31ad0e77d6f..00000000000
--- a/spec/frontend/lib/utils/undo_stack_spec.js
+++ /dev/null
@@ -1,237 +0,0 @@
-import UndoStack from '~/lib/utils/undo_stack';
-
-import { isEqual } from 'underscore';
-
-describe('UndoStack', () => {
- let stack;
-
- beforeEach(() => {
- stack = new UndoStack();
- });
-
- afterEach(() => {
- // Make sure there's not pending saves
- const history = Array.from(stack.history);
- jest.runAllTimers();
- expect(stack.history).toEqual(history);
- });
-
- it('is blank on construction', () => {
- expect(stack.isEmpty()).toBe(true);
- expect(stack.history).toEqual([]);
- expect(stack.cursor).toBe(-1);
- expect(stack.canUndo()).toBe(false);
- expect(stack.canRedo()).toBe(false);
- });
-
- it('handles simple undo/redo behaviour', () => {
- stack.save(10);
- stack.save(11);
- stack.save(12);
-
- expect(stack.history).toEqual([10, 11, 12]);
- expect(stack.cursor).toBe(2);
- expect(stack.current()).toBe(12);
- expect(stack.isEmpty()).toBe(false);
- expect(stack.canUndo()).toBe(true);
- expect(stack.canRedo()).toBe(false);
-
- stack.undo();
- expect(stack.history).toEqual([10, 11, 12]);
- expect(stack.current()).toBe(11);
- expect(stack.canUndo()).toBe(true);
- expect(stack.canRedo()).toBe(true);
-
- stack.undo();
- expect(stack.current()).toBe(10);
- expect(stack.canUndo()).toBe(false);
- expect(stack.canRedo()).toBe(true);
-
- stack.redo();
- expect(stack.current()).toBe(11);
-
- stack.redo();
- expect(stack.current()).toBe(12);
- expect(stack.isEmpty()).toBe(false);
- expect(stack.canUndo()).toBe(true);
- expect(stack.canRedo()).toBe(false);
-
- // Saving should clear the redo stack
- stack.undo();
- stack.save(13);
- expect(stack.history).toEqual([10, 11, 13]);
- expect(stack.current()).toBe(13);
- });
-
- it('clear() should clear the undo history', () => {
- stack.save(0);
- stack.save(1);
- stack.save(2);
- stack.clear();
- expect(stack.history).toEqual([]);
- expect(stack.current()).toBeUndefined();
- });
-
- it('undo and redo are no-ops if unavailable', () => {
- stack.save(10);
- expect(stack.canRedo()).toBe(false);
- expect(stack.canUndo()).toBe(false);
-
- stack.save(11);
- expect(stack.canRedo()).toBe(false);
- expect(stack.canUndo()).toBe(true);
-
- expect(stack.redo()).toBeUndefined();
- expect(stack.history).toEqual([10, 11]);
- expect(stack.current()).toBe(11);
- expect(stack.canRedo()).toBe(false);
- expect(stack.canUndo()).toBe(true);
-
- expect(stack.undo()).toBe(10);
- expect(stack.undo()).toBeUndefined();
- expect(stack.history).toEqual([10, 11]);
- expect(stack.current()).toBe(10);
- expect(stack.canRedo()).toBe(true);
- expect(stack.canUndo()).toBe(false);
- });
-
- it('should not save a duplicate state', () => {
- stack.save(10);
- stack.save(11);
- stack.save(11);
- stack.save(10);
- stack.save(10);
-
- expect(stack.history).toEqual([10, 11, 10]);
- });
-
- it('uses the === operator to detect duplicates', () => {
- stack.save(10);
- stack.save(10);
- expect(stack.history).toEqual([10]);
-
- // eslint-disable-next-line eqeqeq
- expect(2 == '2' && '2' == 2).toBe(true);
- stack.clear();
- stack.save(2);
- stack.save(2);
- stack.save('2');
- stack.save('2');
- stack.save(2);
- expect(stack.history).toEqual([2, '2', 2]);
-
- const obj = {};
- stack.clear();
- stack.save(obj);
- stack.save(obj);
- stack.save({});
- stack.save({});
- expect(stack.history).toEqual([{}, {}, {}]);
- });
-
- it('should allow custom comparators', () => {
- stack.comparator = isEqual;
- const obj = {};
- stack.clear();
- stack.save(obj);
- stack.save(obj);
- stack.save({});
- stack.save({});
- expect(stack.history).toEqual([{}]);
- });
-
- it('should enforce a max number of undo states', () => {
- // Try 2000 saves. Only the last 1000 should be preserved.
- const sequence = Array(2000)
- .fill(0)
- .map((el, i) => i);
- sequence.forEach(stack.save.bind(stack));
- expect(stack.history.length).toBe(1000);
- expect(stack.history).toEqual(sequence.slice(1000));
- expect(stack.current()).toBe(1999);
- expect(stack.canUndo()).toBe(true);
- expect(stack.canRedo()).toBe(false);
-
- // Saving drops the oldest elements from the stack
- stack.save('end');
- expect(stack.history.length).toBe(1000);
- expect(stack.current()).toBe('end');
- expect(stack.history).toEqual([...sequence.slice(1001), 'end']);
-
- // If states were undone but the history is full, can still add.
- stack.undo();
- stack.undo();
- expect(stack.current()).toBe(1998);
- stack.save(3000);
- expect(stack.history.length).toBe(999);
- // should be [1001, 1002, ..., 1998, 3000]
- expect(stack.history).toEqual([...sequence.slice(1001, 1999), 3000]);
-
- // Try a different max length
- stack = new UndoStack(2);
- stack.save(0);
- expect(stack.history).toEqual([0]);
- stack.save(1);
- expect(stack.history).toEqual([0, 1]);
- stack.save(2);
- expect(stack.history).toEqual([1, 2]);
- });
-
- describe('scheduled saves', () => {
- it('should work', () => {
- // Schedules 1000 ms ahead by default
- stack.save(0);
- stack.scheduleSave(1);
- expect(stack.history).toEqual([0]);
- jest.advanceTimersByTime(999);
- expect(stack.history).toEqual([0]);
- jest.advanceTimersByTime(1);
- expect(stack.history).toEqual([0, 1]);
- });
-
- it('should have an adjustable delay', () => {
- stack.scheduleSave(2, 100);
- jest.advanceTimersByTime(100);
- expect(stack.history).toEqual([2]);
- });
-
- it('should cancel previous scheduled saves', () => {
- stack.scheduleSave(3);
- jest.advanceTimersByTime(100);
- stack.scheduleSave(4);
- jest.runAllTimers();
- expect(stack.history).toEqual([4]);
- });
-
- it('should be canceled by explicit saves', () => {
- stack.scheduleSave(5);
- stack.save(6);
- jest.runAllTimers();
- expect(stack.history).toEqual([6]);
- });
-
- it('should be canceled by undos and redos', () => {
- stack.save(1);
- stack.save(2);
- stack.scheduleSave(3);
- stack.undo();
- jest.runAllTimers();
- expect(stack.history).toEqual([1, 2]);
- expect(stack.current()).toBe(1);
-
- stack.scheduleSave(4);
- stack.redo();
- jest.runAllTimers();
- expect(stack.history).toEqual([1, 2]);
- expect(stack.current()).toBe(2);
- });
-
- it('should be persisted immediately with saveNow()', () => {
- stack.scheduleSave(7);
- stack.scheduleSave(8);
- stack.saveNow();
- jest.runAllTimers();
- expect(stack.history).toEqual([8]);
- });
- });
-});