arthur/frontend/test/arthur/domain/history_test.cljs
Olive Vaughn 7aaf0a15bd Inspector number boxes edit as you type, and are one undo step per focus
The boxes wrote nothing until blur, so a spinner click showed nothing on
screen. Now every keystroke and step is an edit, and history holds the
step open from focus to blur, so typing 4 then 5 is seen as 4, then 45,
and undone once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 01:35:52 -04:00

74 lines
3.3 KiB
Clojure

(ns arthur.domain.history-test
(:require [cljs.test :refer [deftest is testing]]
[arthur.domain.history :as history]))
(def empty-doc {"t" 1})
(deftest undo-and-redo-walk-your-own-steps
(let [made (assoc empty-doc "b" :shape)
moved (assoc made "b" :moved)
h (-> nil
(history/record empty-doc made 0)
(history/record made moved 5000))
one (history/undo h moved)
two (history/undo (:history one) (:leaves one))]
(is (= made (:leaves one)))
(is (= empty-doc (:leaves two)))
(is (nil? (history/undo (:history two) (:leaves two))))
(is (= made (:leaves (history/redo (:history two) (:leaves two)))))))
(deftest a-drag-is-one-step
(let [h (reduce (fn [h [x t]] (history/record h {"v" (dec x)} {"v" x} t))
nil [[1 0] [2 100] [3 200]])]
(is (= 1 (count (:done h))))
(is (= {"v" 0} (:leaves (history/undo h {"v" 3}))))))
(deftest typing-into-a-field-is-one-step-however-slow
(let [h (-> nil
(history/record {"w" 1} {"w" 2} 0)
history/hold
(history/record {"w" 2} {"w" 4} 100)
(history/record {"w" 4} {"w" 45} 9000)
history/settle
(history/record {"w" 45} {"w" 46} 9100))]
(is (= 3 (count (:done h))) "the edit before focus and the one after blur stand apart")
(is (= {"w" 2} (:leaves (history/undo (:history (history/undo h {"w" 46})) {"w" 45}))))))
(deftest their-write-between-two-of-mine-keeps-them-apart
(let [h (-> nil
(history/record {"fps" 30} {"fps" 12} 0)
;; theirs lands: 12 -> 9, not recorded
(history/record {"fps" 9} {"fps" 15} 300))]
(is (= 2 (count (:done h))))
(is (= {"fps" 9} (:leaves (history/undo h {"fps" 15}))))))
(deftest undo-never-takes-somebody-elses-work
(testing "I make b; they edit it; I edit it; I undo twice"
(let [made {"b" :shape}
theirs {"b" :their-edit}
mine {"b" :my-edit}
h (-> nil
(history/record {} made 0)
;; their edit arrives as a remote write: not recorded
(history/record theirs mine 5000))
one (history/undo h mine)
two (history/undo (:history one) (:leaves one))]
(is (= theirs (:leaves one)) "my edit comes off, theirs is what is left")
(is (:blocked two) "removing b would remove their edit, so it is refused")
(is (empty? (:done (:history two))) "and the refused step is dropped"))))
(deftest a-new-edit-clears-redo
(let [h (history/record nil {} {"a" 1} 0)
u (history/undo h {"a" 1})
h (history/record (:history u) (:leaves u) {"c" 1} 9000)]
(is (nil? (history/redo h {"c" 1})))))
(deftest a-step-says-what-it-was
(let [node "clip/u/symbol/main/node/b"
pts "clip/u/symbol/main/channel/b/geom.pts"
made {node {:id :b :name "shape 3"} pts :p}]
(is (= "add shape 3" (history/label {} made [node pts])))
(is (= "edit shape 3" (history/label made (assoc made pts :q) [pts])))
(is (= "delete shape 3" (history/label made {} [node pts])))
(is (= "project settings" (history/label {} {"clip/u/timing" {:fps 9}} ["clip/u/timing"])))
(is (= ["add shape 3"] (:done (history/steps (history/record nil {} made 0)))))))