@@ -4,28 +4,22 @@ import { expect } from "@open-wc/testing";
44import { assert , property } from "fast-check" ;
55
66import {
7- insert ,
8- isValidInsert ,
9- remove ,
107 sclDocString ,
11- setAttributes ,
12- setTextContent ,
138 testDocs ,
149 UndoRedoTestCase ,
1510 undoRedoTestCases ,
16- xmlAttributeName ,
1711} from "./testHelpers.js" ;
1812
1913import { EditV2 , isSetAttributes , isSetTextContent } from "./editv2.js" ;
2014
2115import { XMLEditor } from "./XMLEditor.js" ;
22- import { Transactor } from "./Transactor.js" ;
16+ import { Commit , Transactor } from "./Transactor.js" ;
2317
24- describe ( "Utility function to handle EditV2 edits " , ( ) => {
18+ describe ( "XMLEditor " , ( ) => {
2519 let editor : Transactor < EditV2 > ;
2620 let sclDoc : XMLDocument ;
2721
28- beforeEach ( async ( ) => {
22+ beforeEach ( ( ) => {
2923 editor = new XMLEditor ( ) ;
3024 sclDoc = new DOMParser ( ) . parseFromString ( sclDocString , "application/xml" ) ;
3125 } ) ;
@@ -63,14 +57,6 @@ describe("Utility function to handle EditV2 edits", () => {
6357 "myns:attr" : "value1" ,
6458 "myns:attr2" : "value1" ,
6559 } ,
66- "http://example.org/myns2" : {
67- attr : "value2" ,
68- attr2 : "value2" ,
69- } ,
70- "http://example.org/myns3" : {
71- attr : "value3" ,
72- attr2 : "value3" ,
73- } ,
7460 } ,
7561 } ,
7662 { } ,
@@ -81,10 +67,6 @@ describe("Utility function to handle EditV2 edits", () => {
8167 expect ( element . getAttribute ( "__proto__" ) ) . to . equal ( "a string" ) ;
8268 expect ( element . getAttribute ( "myns:attr" ) ) . to . equal ( "value1" ) ;
8369 expect ( element . getAttribute ( "myns:attr2" ) ) . to . equal ( "value1" ) ;
84- expect ( element . getAttribute ( "ens2:attr" ) ) . to . equal ( "value2" ) ;
85- expect ( element . getAttribute ( "ens2:attr2" ) ) . to . equal ( "value2" ) ;
86- expect ( element . getAttribute ( "ens3:attr" ) ) . to . equal ( "value3" ) ;
87- expect ( element . getAttribute ( "ens3:attr2" ) ) . to . equal ( "value3" ) ;
8870 } ) ;
8971
9072 it ( "sets an element's textContent on SetTextContent" , ( ) => {
@@ -99,6 +81,33 @@ describe("Utility function to handle EditV2 edits", () => {
9981 expect ( element . textContent ) . to . equal ( newTextContent ) ;
10082 } ) ;
10183
84+ it ( "records a commit history" , ( ) => {
85+ const node = sclDoc . querySelector ( "Substation" ) ! ;
86+ const edit = { node } ;
87+ editor . commit ( edit ) ;
88+ expect ( editor . past ) . to . have . lengthOf ( 1 ) ;
89+ expect ( editor . past [ 0 ] )
90+ . to . exist . and . property ( "redo" )
91+ . to . have . lengthOf ( 1 )
92+ . and . to . include ( edit ) ;
93+ } ) ;
94+
95+ it ( "records a given title in the commit history" , ( ) => {
96+ const node = sclDoc . querySelector ( "SCL" ) ! ;
97+
98+ editor . commit (
99+ {
100+ node,
101+ } ,
102+ { title : "delete everything" } ,
103+ ) ;
104+
105+ expect ( editor . past [ editor . past . length - 1 ] ) . to . have . property (
106+ "title" ,
107+ "delete everything" ,
108+ ) ;
109+ } ) ;
110+
102111 it ( "squashes multiple edits into a single undoable edit" , ( ) => {
103112 const element = sclDoc . querySelector ( "Substation" ) ! ;
104113
@@ -165,104 +174,79 @@ describe("Utility function to handle EditV2 edits", () => {
165174 it ( "undoes a committed edit on undo() call" , ( ) => {
166175 const node = sclDoc . querySelector ( "Substation" ) ! ;
167176
168- editor . commit ( { node } ) ;
169- editor . undo ( ) ;
177+ const commit = editor . commit ( { node } ) ;
178+ const undone = editor . undo ( ) ;
170179
180+ expect ( undone ) . to . exist . and . to . equal ( commit ) ;
171181 expect ( sclDoc . querySelector ( "Substation" ) ) . to . exist ;
172182 } ) ;
173183
174184 it ( "redoes an undone edit on redo() call" , ( ) => {
175185 const node = sclDoc . querySelector ( "Substation" ) ! ;
176186
177- editor . commit ( { node } ) ;
187+ const commit = editor . commit ( { node } ) ;
178188 editor . undo ( ) ;
179- editor . redo ( ) ;
189+ const redone = editor . redo ( ) ;
180190
191+ expect ( redone ) . to . exist . and . to . equal ( commit ) ;
181192 expect ( sclDoc . querySelector ( "Substation" ) ) . to . be . null ;
182193 } ) ;
183194
184- describe ( "generally" , ( ) => {
185- it ( "inserts elements on Insert edit events" , ( ) =>
186- assert (
187- property (
188- testDocs . chain ( ( [ doc1 , doc2 ] ) => {
189- const nodes = doc1 . nodes . concat ( doc2 . nodes ) ;
190- return insert ( nodes ) ;
191- } ) ,
192- ( edit ) => {
193- editor . commit ( edit ) ;
194- if ( isValidInsert ( edit ) )
195- return (
196- edit . node . parentElement === edit . parent &&
197- edit . node . nextSibling === edit . reference
198- ) ;
199- return true ;
200- } ,
201- ) ,
202- ) ) ;
195+ it ( "undoes nothing at the beginning of the history" , ( ) => {
196+ const node = sclDoc . querySelector ( "Substation" ) ! ;
203197
204- it ( "set's an element's textContent on SetTextContent edit events" , ( ) =>
205- assert (
206- property (
207- testDocs . chain ( ( [ doc1 , doc2 ] ) => {
208- const nodes = doc1 . nodes . concat ( doc2 . nodes ) ;
209- return setTextContent ( nodes ) ;
210- } ) ,
211- ( edit ) => {
212- editor . commit ( edit ) ;
213-
214- return edit . element . textContent === edit . textContent ;
215- } ,
216- ) ,
217- ) ) ;
198+ editor . commit ( { node } ) ;
199+ editor . undo ( ) ;
200+ const secondUndo = editor . undo ( ) ;
218201
219- it ( "updates default- and foreign-namespace attributes on UpdateNS events" , ( ) =>
220- assert (
221- property (
222- testDocs . chain ( ( [ { nodes } ] ) => setAttributes ( nodes ) ) ,
223- ( edit ) => {
224- editor . commit ( edit ) ;
225- return (
226- Object . entries ( edit . attributes )
227- . filter ( ( [ name ] ) => xmlAttributeName . test ( name ) )
228- . map ( ( entry ) => entry as [ string , string | null ] )
229- . every (
230- ( [ name , value ] ) => edit . element . getAttribute ( name ) === value ,
231- ) &&
232- Object . entries ( edit . attributesNS )
233- . map (
234- ( entry ) => entry as [ string , Record < string , string | null > ] ,
235- )
236- . every ( ( [ ns , attributes ] ) =>
237- Object . entries ( attributes )
238- . filter ( ( [ name ] ) => xmlAttributeName . test ( name ) )
239- . map ( ( entry ) => entry as [ string , string | null ] )
240- . every (
241- ( [ name , value ] ) =>
242- edit . element . getAttributeNS (
243- ns ,
244- name . includes ( ":" )
245- ? < string > name . split ( ":" , 2 ) [ 1 ]
246- : name ,
247- ) === value ,
248- ) ,
249- )
250- ) ;
251- } ,
252- ) ,
253- ) ) . timeout ( 20000 ) ;
202+ expect ( secondUndo ) . to . not . exist ;
203+ } ) ;
254204
255- it ( "removes elements on Remove edit events" , ( ) =>
256- assert (
257- property (
258- testDocs . chain ( ( [ { nodes } ] ) => remove ( nodes ) ) ,
259- ( { node } ) => {
260- editor . commit ( { node } ) ;
261- return ! node . parentNode ;
262- } ,
263- ) ,
264- ) ) ;
205+ it ( "redoes nothing at the end of the history" , ( ) => {
206+ const node = sclDoc . querySelector ( "Substation" ) ! ;
265207
208+ editor . commit ( { node } ) ;
209+ const redo = editor . redo ( ) ;
210+
211+ expect ( redo ) . to . not . exist ;
212+ } ) ;
213+
214+ it ( "allows the user to subscribe to commits and to unsubscribe" , ( ) => {
215+ const node = sclDoc . querySelector ( "Substation" ) ! ;
216+ const edit = { node } ;
217+ let committed : Commit < EditV2 > | undefined ;
218+ let called = 0 ;
219+ const callback = ( commit : Commit < EditV2 > ) => {
220+ committed = commit ;
221+ called ++ ;
222+ } ;
223+ const unsubscribe = editor . subscribe ( callback ) ;
224+ editor . commit ( edit , { title : "test" } ) ;
225+ expect ( committed ) . to . exist . and . to . have . property ( "redo" ) . to . include ( edit ) ;
226+ expect ( committed ) . to . have . property ( "title" , "test" ) ;
227+ expect ( called ) . to . equal ( 1 ) ;
228+ expect ( editor . past ) . to . have . lengthOf ( 1 ) ;
229+
230+ editor . undo ( ) ;
231+ expect ( called ) . to . equal ( 1 ) ;
232+ expect ( editor . past ) . to . have . lengthOf ( 0 ) ;
233+ expect ( editor . future ) . to . have . lengthOf ( 1 ) ;
234+
235+ editor . redo ( ) ;
236+ expect ( called ) . to . equal ( 1 ) ;
237+ expect ( editor . past ) . to . have . lengthOf ( 1 ) ;
238+ expect ( editor . future ) . to . have . lengthOf ( 0 ) ;
239+
240+ const unsubscribed = unsubscribe ( ) ;
241+ expect ( unsubscribed ) . to . equal ( callback ) ;
242+
243+ editor . commit ( edit , { title : "some other title, not test" } ) ;
244+ expect ( committed ) . to . have . property ( "title" , "test" ) ;
245+ expect ( called ) . to . equal ( 1 ) ;
246+ expect ( editor . past ) . to . have . lengthOf ( 2 ) ;
247+ } ) ;
248+
249+ describe ( "generally" , ( ) => {
266250 it ( "undoes up to n edits on undo(n) call" , ( ) =>
267251 assert (
268252 property (
@@ -272,9 +256,13 @@ describe("Utility function to handle EditV2 edits", () => {
272256 doc . cloneNode ( true ) ,
273257 ) ;
274258 edits . forEach ( ( a : EditV2 ) => {
275- editor . commit ( a , { squash } ) ;
259+ try {
260+ editor . commit ( a , { squash } ) ;
261+ } catch ( e ) {
262+ console . log ( "error" , e ) ;
263+ }
276264 } ) ;
277- while ( editor . canUndo ) editor . undo ( ) ;
265+ while ( editor . past . length ) editor . undo ( ) ;
278266 expect ( doc1 ) . to . satisfy ( ( doc : XMLDocument ) =>
279267 doc . isEqualNode ( oldDoc1 ) ,
280268 ) ;
@@ -298,8 +286,8 @@ describe("Utility function to handle EditV2 edits", () => {
298286 new XMLSerializer ( ) . serializeToString ( doc ) ,
299287 ) ;
300288
301- while ( editor . canUndo ) editor . undo ( ) ;
302- while ( editor . canRedo ) editor . redo ( ) ;
289+ while ( editor . past . length ) editor . undo ( ) ;
290+ while ( editor . future . length ) editor . redo ( ) ;
303291 const [ newDoc1 , newDoc2 ] = [ doc1 , doc2 ] . map ( ( doc ) =>
304292 new XMLSerializer ( ) . serializeToString ( doc ) ,
305293 ) ;
0 commit comments