Skip to content

Commit

Permalink
Core Data: Fix redo behavior and expand test coverage. (#17827)
Browse files Browse the repository at this point in the history
* Core Data: Fix redo behavior and expand test coverage.

* e2e test: compare text content instead of matching snapshots
  • Loading branch information
epiqueras authored and ellatrix committed Oct 8, 2019
1 parent 7110f85 commit 9de487d
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 24 deletions.
19 changes: 11 additions & 8 deletions packages/core-data/src/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ export function undo( state = UNDO_INITIAL_STATE, action ) {
switch ( action.type ) {
case 'EDIT_ENTITY_RECORD':
case 'CREATE_UNDO_LEVEL':
if ( action.type === 'CREATE_UNDO_LEVEL' ) {
const isCreateUndoLevel = action.type === 'CREATE_UNDO_LEVEL';
if ( isCreateUndoLevel ) {
action = lastEditAction;
} else {
lastEditAction = action;
Expand All @@ -328,7 +329,7 @@ export function undo( state = UNDO_INITIAL_STATE, action ) {
// Transient edits don't create an undo level, but are
// reachable in the next meaningful edit to which they
// are merged. They are defined in the entity's config.
if ( ! Object.keys( action.edits ).some( ( key ) => ! action.transientEdits[ key ] ) ) {
if ( ! isCreateUndoLevel && ! Object.keys( action.edits ).some( ( key ) => ! action.transientEdits[ key ] ) ) {
const nextState = [ ...state ];
nextState.flattenedUndo = { ...state.flattenedUndo, ...action.edits };
nextState.offset = state.offset;
Expand All @@ -339,12 +340,14 @@ export function undo( state = UNDO_INITIAL_STATE, action ) {
const nextState = state.slice( 0, state.offset || undefined );
nextState.offset = 0;
nextState.pop();
nextState.push( {
kind: action.meta.undo.kind,
name: action.meta.undo.name,
recordId: action.meta.undo.recordId,
edits: { ...state.flattenedUndo, ...action.meta.undo.edits },
} );
if ( ! isCreateUndoLevel ) {
nextState.push( {
kind: action.meta.undo.kind,
name: action.meta.undo.name,
recordId: action.meta.undo.recordId,
edits: { ...state.flattenedUndo, ...action.meta.undo.edits },
} );
}
// When an edit is a function it's an optimization to avoid running some expensive operation.
// We can't rely on the function references being the same so we opt out of comparing them here.
const comparisonUndoEdits = Object.values( action.meta.undo.edits ).filter( ( edit ) => typeof edit !== 'function' );
Expand Down
14 changes: 0 additions & 14 deletions packages/e2e-tests/specs/__snapshots__/undo.test.js.snap
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`undo Should undo to expected level intervals 1`] = `
"<!-- wp:paragraph -->
<p>This</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>is</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>test</p>
<!-- /wp:paragraph -->"
`;

exports[`undo should immediately create an undo level on typing 1`] = `
"<!-- wp:paragraph -->
<p>1</p>
Expand Down
61 changes: 59 additions & 2 deletions packages/e2e-tests/specs/undo.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,27 +54,84 @@ describe( 'undo', () => {
expect( await getEditedPostContent() ).toBe( '' );
} );

it( 'Should undo to expected level intervals', async () => {
it( 'Should undo/redo to expected level intervals', async () => {
await clickBlockAppender();

const firstBlock = await getEditedPostContent();

await page.keyboard.type( 'This' );

const firstText = await getEditedPostContent();

await page.keyboard.press( 'Enter' );

const secondBlock = await getEditedPostContent();

await page.keyboard.type( 'is' );

const secondText = await getEditedPostContent();

await page.keyboard.press( 'Enter' );

const thirdBlock = await getEditedPostContent();

await page.keyboard.type( 'test' );

expect( await getEditedPostContent() ).toMatchSnapshot();
const thirdText = await getEditedPostContent();

await new Promise( ( resolve ) => setTimeout( resolve, 1000 ) );

await pressKeyWithModifier( 'primary', 'z' ); // Undo 3rd paragraph text.

expect( await getEditedPostContent() ).toBe( thirdBlock );

await pressKeyWithModifier( 'primary', 'z' ); // Undo 3rd block.

expect( await getEditedPostContent() ).toBe( secondText );

await pressKeyWithModifier( 'primary', 'z' ); // Undo 2nd paragraph text.

expect( await getEditedPostContent() ).toBe( secondBlock );

await pressKeyWithModifier( 'primary', 'z' ); // Undo 2nd block.

expect( await getEditedPostContent() ).toBe( firstText );

await pressKeyWithModifier( 'primary', 'z' ); // Undo 1st paragraph text.

expect( await getEditedPostContent() ).toBe( firstBlock );

await pressKeyWithModifier( 'primary', 'z' ); // Undo 1st block.

expect( await getEditedPostContent() ).toBe( '' );
// After undoing every action, there should be no more undo history.
expect( await page.$( '.editor-history__undo[aria-disabled="true"]' ) ).not.toBeNull();

await pressKeyWithModifier( 'primaryShift', 'z' ); // Redo 1st block.

expect( await getEditedPostContent() ).toBe( firstBlock );
// After redoing one change, the undo button should be enabled again.
expect( await page.$( '.editor-history__undo[aria-disabled="true"]' ) ).toBeNull();

await pressKeyWithModifier( 'primaryShift', 'z' ); // Redo 1st paragraph text.

expect( await getEditedPostContent() ).toBe( firstText );

await pressKeyWithModifier( 'primaryShift', 'z' ); // Redo 2nd block.

expect( await getEditedPostContent() ).toBe( secondBlock );

await pressKeyWithModifier( 'primaryShift', 'z' ); // Redo 2nd paragraph text.

expect( await getEditedPostContent() ).toBe( secondText );

await pressKeyWithModifier( 'primaryShift', 'z' ); // Redo 3rd block.

expect( await getEditedPostContent() ).toBe( thirdBlock );

await pressKeyWithModifier( 'primaryShift', 'z' ); // Redo 3rd paragraph text.

expect( await getEditedPostContent() ).toBe( thirdText );
} );

it( 'should undo for explicit persistence editing post', async () => {
Expand Down

0 comments on commit 9de487d

Please sign in to comment.