== insertText undo/redo round trip ==
PASS: fresh host canUndo=false canRedo=false
PASS: after insertText DOM
PASS: after insertText selection
PASS: after insertText canUndo=true canRedo=false
PASS: execCommand undo returns true
PASS: after undo DOM
PASS: after undo selection
PASS: after undo canUndo=false canRedo=true
PASS: after undo events
PASS: execCommand redo returns true
PASS: after redo DOM
PASS: after redo selection
PASS: after redo canUndo=true canRedo=false
PASS: after redo events
== empty history: execCommand returns false, no events ==
PASS: undo on empty history returns false
PASS: redo on empty history returns false
PASS: empty history events
== a new edit after undo discards the redo stack ==
PASS: after new edit canUndo=true canRedo=false
PASS: redo after new edit returns false
PASS: redo did nothing DOM
== repeated undo at the beginning and redo at the end ==
PASS: second undo returns false
PASS: exhausted undo DOM
PASS: second redo returns false
PASS: exhausted redo DOM
== replacing a selection with typed text restores it on undo ==
PASS: after replace DOM
PASS: after replace selection
PASS: undo restores forward selection DOM
PASS: undo restores forward selection selection
PASS: redo restores caret DOM
PASS: redo restores caret selection
== backward selection direction is restored on undo ==
PASS: after replace DOM
PASS: after replace selection
PASS: undo restores backward selection DOM
PASS: undo restores backward selection selection
== deleting a paragraph boundary and undoing it ==
PASS: after merge DOM
PASS: undo restores paragraphs DOM
PASS: redo merges again DOM
== insertParagraph and insertLineBreak undo/redo ==
PASS: after line break DOM
PASS: undo removes line break DOM
PASS: undo removes line break selection
PASS: redo re-inserts line break DOM
PASS: after paragraph split DOM
PASS: undo merges paragraph back DOM
PASS: undo merges paragraph back selection
PASS: redo splits paragraph again DOM
== edits spanning adjacent styled text nodes ==
PASS: after styled-boundary delete DOM
PASS: undo restores styled runs DOM
PASS: undo restores styled runs selection
PASS: redo deletes styled runs again DOM
== undo of a node-removing edit re-inserts the original node ==
PASS: delete removed the image
PASS: undo re-inserted the same image node object
PASS: redo removed the image again
PASS: second undo still re-inserts the same node object
== formatting commands participate in history ==
PASS: after bold DOM
PASS: undo removes bold DOM
PASS: undo removes bold selection
PASS: redo restores bold DOM
== script-driven DOM mutations do not enter the history ==
PASS: undo removed only the edit DOM
PASS: script mutation recorded nothing canUndo=false canRedo=true
== undo after script removed the edited node is a safe no-op ==
PASS: undo on mangled DOM changed nothing DOM
PASS: the invalidated entry was dropped canUndo=false canRedo=false
PASS: redo has nothing to replay
PASS: redo on mangled DOM changed nothing DOM
== undo after script rewrote the edited text is a safe no-op ==
PASS: undo on rewritten text changed nothing DOM
PASS: the invalidated entry was dropped canUndo=false canRedo=false
== multiple editing hosts share one history stack ==
PASS: first undo reverts the most recent host
PASS: second undo reverts the older host
PASS: first redo replays the older host
PASS: second redo replays the newer host
== removing an editing host retires its history entries ==
PASS: before host removal canUndo=true canRedo=false
PASS: after host removal canUndo=false canRedo=false
