@@ -312,6 +312,137 @@ describe('InputEditor', function() {
312312
313313 } ) ;
314314
315+
316+ describe ( 'undo/redo' , function ( ) {
317+
318+ const isMac = / M a c / . test ( navigator . platform ) ;
319+ const undoKeys = isMac ? '{Meta>}z{/Meta}' : '{Control>}z{/Control}' ;
320+ const redoKeys = isMac ? '{Meta>}{Shift>}z{/Shift}{/Meta}' : '{Control>}y{/Control}' ;
321+
322+
323+ it ( 'should undo typing' , async function ( ) {
324+
325+ // given
326+ const onChangeSpy = sinon . spy ( ) ;
327+
328+ const { getByRole } = renderWithProps ( {
329+ value : '{}' ,
330+ onChange : onChangeSpy
331+ } ) ;
332+
333+ const textbox = getByRole ( 'textbox' ) ;
334+ await user . click ( textbox ) ;
335+
336+ // when - type something
337+ await user . keyboard ( '{ArrowRight}{Enter}"a": 1' ) ;
338+
339+ // assume - typing happened
340+ await waitFor ( ( ) => {
341+ expect ( onChangeSpy ) . to . have . been . called ;
342+ } ) ;
343+
344+ const valueAfterTyping = onChangeSpy . lastCall . args [ 0 ] ;
345+ expect ( valueAfterTyping ) . to . contain ( '"a": 1' ) ;
346+
347+ onChangeSpy . resetHistory ( ) ;
348+
349+ // when - undo
350+ await user . keyboard ( undoKeys ) ;
351+
352+ // then - onChange should fire with reverted content
353+ await waitFor ( ( ) => {
354+ expect ( onChangeSpy ) . to . have . been . called ;
355+ } ) ;
356+ } ) ;
357+
358+
359+ it ( 'should undo reset' , async function ( ) {
360+
361+ // given
362+ const onChangeSpy = sinon . spy ( ) ;
363+ const originalValue = '{\n "foo": "bar"\n}' ;
364+ const resetValue = '{}' ;
365+
366+ const { container, getByRole, rerender } = renderWithProps ( {
367+ value : originalValue ,
368+ onChange : onChangeSpy
369+ } ) ;
370+
371+ // assume - editor shows original value
372+ expect ( container . textContent ) . to . contain ( '"foo": "bar"' ) ;
373+
374+ // when - simulate reset by changing value prop
375+ rerender (
376+ < InputEditor
377+ value = { resetValue }
378+ onChange = { onChangeSpy }
379+ onErrorChange = { ( ) => { } }
380+ />
381+ ) ;
382+
383+ await waitFor ( ( ) => {
384+ expect ( container . textContent ) . to . not . contain ( '"foo": "bar"' ) ;
385+ } ) ;
386+
387+ // when - undo the reset
388+ const textbox = getByRole ( 'textbox' ) ;
389+ await user . click ( textbox ) ;
390+ await user . keyboard ( undoKeys ) ;
391+
392+ // then - editor should revert to original value
393+ await waitFor ( ( ) => {
394+ expect ( onChangeSpy ) . to . have . been . calledWith ( originalValue ) ;
395+ } ) ;
396+ } ) ;
397+
398+
399+ it ( 'should redo after undo' , async function ( ) {
400+
401+ // given
402+ const onChangeSpy = sinon . spy ( ) ;
403+ const originalValue = '{\n "foo": "bar"\n}' ;
404+ const resetValue = '{}' ;
405+
406+ const { container, getByRole, rerender } = renderWithProps ( {
407+ value : originalValue ,
408+ onChange : onChangeSpy
409+ } ) ;
410+
411+ // reset
412+ rerender (
413+ < InputEditor
414+ value = { resetValue }
415+ onChange = { onChangeSpy }
416+ onErrorChange = { ( ) => { } }
417+ />
418+ ) ;
419+
420+ await waitFor ( ( ) => {
421+ expect ( container . textContent ) . to . not . contain ( '"foo": "bar"' ) ;
422+ } ) ;
423+
424+ // undo
425+ const textbox = getByRole ( 'textbox' ) ;
426+ await user . click ( textbox ) ;
427+ await user . keyboard ( undoKeys ) ;
428+
429+ await waitFor ( ( ) => {
430+ expect ( onChangeSpy ) . to . have . been . calledWith ( originalValue ) ;
431+ } ) ;
432+
433+ onChangeSpy . resetHistory ( ) ;
434+
435+ // when - redo
436+ await user . keyboard ( redoKeys ) ;
437+
438+ // then - should go back to reset value
439+ await waitFor ( ( ) => {
440+ expect ( onChangeSpy ) . to . have . been . calledWith ( resetValue ) ;
441+ } ) ;
442+ } ) ;
443+
444+ } ) ;
445+
315446} ) ;
316447
317448function renderWithProps ( props = { } ) {
0 commit comments