mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-15 14:20:38 +08:00
142 lines
4.5 KiB
Text
142 lines
4.5 KiB
Text
|
import {Actions, Task, UndoRedoStore} from 'nylas-exports'
|
||
|
|
||
|
class Undoable extends Task {
|
||
|
canBeUndone() {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
createIdenticalTask() {
|
||
|
const t = new Undoable()
|
||
|
t.id = this.id
|
||
|
return t
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class PermanentTask extends Task {
|
||
|
canBeUndone() {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
describe("UndoRedoStore", function undoRedoStoreSpec() {
|
||
|
beforeEach(() => {
|
||
|
UndoRedoStore._undo = []
|
||
|
UndoRedoStore._redo = []
|
||
|
spyOn(UndoRedoStore, "trigger")
|
||
|
spyOn(Actions, "undoTaskId")
|
||
|
spyOn(Actions, "queueTask").andCallFake((...args) => {
|
||
|
UndoRedoStore._onQueue(...args)
|
||
|
});
|
||
|
spyOn(Actions, "queueTasks").andCallFake((...args) => {
|
||
|
UndoRedoStore._onQueue(...args)
|
||
|
});
|
||
|
|
||
|
this.ids = (arrarr) => arrarr.map((arr) => arr.map((itm) => itm.id))
|
||
|
this.t1 = new Undoable();
|
||
|
this.t2 = new Undoable();
|
||
|
this.t3 = new Undoable();
|
||
|
this.t4 = new Undoable();
|
||
|
this.p1 = new PermanentTask();
|
||
|
this.t1.id = "t1"
|
||
|
this.t2.id = "t2"
|
||
|
this.t3.id = "t3"
|
||
|
this.t4.id = "t4"
|
||
|
this.p1.id = "p1"
|
||
|
});
|
||
|
|
||
|
it("pushes single tasks onto undo/redo", () => {
|
||
|
Actions.queueTask(this.t1)
|
||
|
expect(UndoRedoStore._redo).toEqual([])
|
||
|
expect(UndoRedoStore._undo).toEqual([[this.t1]])
|
||
|
expect(UndoRedoStore.trigger).toHaveBeenCalled()
|
||
|
});
|
||
|
|
||
|
it("pushes multiple tasks onto redo", () => {
|
||
|
Actions.queueTasks([this.t1, this.t2])
|
||
|
expect(UndoRedoStore._redo).toEqual([])
|
||
|
expect(UndoRedoStore._undo).toEqual([[this.t1, this.t2]])
|
||
|
expect(UndoRedoStore.trigger).toHaveBeenCalled()
|
||
|
});
|
||
|
|
||
|
it("only undoes task if they're all 'undoable'", () => {
|
||
|
Actions.queueTask([this.t1, this.p1])
|
||
|
expect(UndoRedoStore._redo).toEqual([])
|
||
|
expect(UndoRedoStore._undo).toEqual([])
|
||
|
expect(UndoRedoStore.trigger).not.toHaveBeenCalled()
|
||
|
});
|
||
|
|
||
|
it("refreshes redo if we get a new task", () => {
|
||
|
UndoRedoStore._redo = [[this.t1, this.t2], [this.t3]]
|
||
|
Actions.queueTask(this.t3)
|
||
|
expect(UndoRedoStore._redo).toEqual([])
|
||
|
});
|
||
|
|
||
|
it("doesn't refresh redo if our task is itself a redo task", () => {
|
||
|
UndoRedoStore._redo = [[this.t1, this.t2], [this.t3]]
|
||
|
const tr = new Undoable()
|
||
|
tr.isRedoTask = true
|
||
|
Actions.queueTask(tr)
|
||
|
expect(UndoRedoStore._redo).toEqual([[this.t1, this.t2], [this.t3]])
|
||
|
expect(UndoRedoStore._undo).toEqual([[tr]])
|
||
|
});
|
||
|
|
||
|
it("runs undoTask on each group of undo tasks", () => {
|
||
|
UndoRedoStore._undo = [[this.t3], [this.t1, this.t2]]
|
||
|
UndoRedoStore.undo()
|
||
|
expect(Actions.undoTaskId.calls.length).toBe(2)
|
||
|
expect(Actions.undoTaskId.calls[0].args[0]).toBe("t1")
|
||
|
expect(Actions.undoTaskId.calls[1].args[0]).toBe("t2")
|
||
|
expect(UndoRedoStore._undo).toEqual([[this.t3]])
|
||
|
});
|
||
|
|
||
|
it("creates identical redo tasks and pushes on the stack", () => {
|
||
|
UndoRedoStore._undo = [[this.t3], [this.t1, this.t2]]
|
||
|
UndoRedoStore.undo()
|
||
|
expect(UndoRedoStore._undo).toEqual([[this.t3]])
|
||
|
expect(UndoRedoStore._redo[0][0].id).toBe("t1")
|
||
|
expect(UndoRedoStore._redo[0][1].id).toBe("t2")
|
||
|
expect(UndoRedoStore._redo.length).toBe(1)
|
||
|
});
|
||
|
|
||
|
it("redoes the latest task", () => {
|
||
|
UndoRedoStore._undo = [[this.t3], [this.t1, this.t2]]
|
||
|
UndoRedoStore.undo()
|
||
|
UndoRedoStore.redo()
|
||
|
expect(Actions.queueTasks.calls[0].args[0][0].id).toBe('t1')
|
||
|
expect(Actions.queueTasks.calls[0].args[0][1].id).toBe('t2')
|
||
|
expect(UndoRedoStore._undo[0]).toEqual([this.t3])
|
||
|
expect(UndoRedoStore._undo[1][0].id).toBe('t1')
|
||
|
expect(UndoRedoStore._undo[1][1].id).toBe('t2')
|
||
|
});
|
||
|
|
||
|
it("marks the incoming task as a redo task", () => {
|
||
|
UndoRedoStore._undo = [[this.t3], [this.t1, this.t2]]
|
||
|
UndoRedoStore.undo()
|
||
|
UndoRedoStore.redo()
|
||
|
expect(Actions.queueTasks.calls[0].args[0][0].isRedoTask).toBe(true)
|
||
|
expect(Actions.queueTasks.calls[0].args[0][1].isRedoTask).toBe(true)
|
||
|
});
|
||
|
|
||
|
it("correctly follows the undo redo sequence of events", () => {
|
||
|
Actions.queueTask(this.t1)
|
||
|
Actions.queueTask(this.t2)
|
||
|
Actions.queueTasks([this.t3, this.t4])
|
||
|
expect(UndoRedoStore._undo).toEqual([[this.t1], [this.t2], [this.t3, this.t4]])
|
||
|
UndoRedoStore.undo()
|
||
|
UndoRedoStore.undo()
|
||
|
UndoRedoStore.undo()
|
||
|
UndoRedoStore.undo()
|
||
|
UndoRedoStore.undo()
|
||
|
expect(UndoRedoStore._undo).toEqual([])
|
||
|
expect(this.ids(UndoRedoStore._redo)).toEqual([["t3", "t4"], ["t2"], ["t1"]])
|
||
|
UndoRedoStore.redo()
|
||
|
UndoRedoStore.redo()
|
||
|
UndoRedoStore.redo()
|
||
|
UndoRedoStore.redo()
|
||
|
UndoRedoStore.redo()
|
||
|
UndoRedoStore.redo()
|
||
|
expect(this.ids(UndoRedoStore._undo)).toEqual([["t1"], ["t2"], ["t3", "t4"]])
|
||
|
expect(this.ids(UndoRedoStore._redo)).toEqual([])
|
||
|
});
|
||
|
});
|