Skip to content

Commit

Permalink
Add test for multiplayer undo
Browse files Browse the repository at this point in the history
  • Loading branch information
mirka committed Nov 12, 2021
1 parent 92b56e5 commit 7859989
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* External dependencies
*/
import { waitFor } from '@testing-library/react';

/**
* Helper to generate mock transport modules for an isolated channel.
*
Expand Down Expand Up @@ -47,3 +52,15 @@ export function getTransports( count ) {
.fill( null )
.map( () => mockTransport() );
}

/**
* Emulate a pause between typing events for Yjs to make a new undo stack item.
*
* Requires jest.useRealTimers().
*
* @param {import('@testing-library/dom').Screen} screen
*/
export async function pauseTyping( screen ) {
screen.getAllByRole( 'document' ).forEach( ( el ) => el.blur() );
await waitFor( () => new Promise( ( resolve ) => setTimeout( resolve, 550 ) ) );
}
68 changes: 63 additions & 5 deletions src/components/collaborative-editing/use-yjs/__tests__/undo.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/**
* External dependencies
*/
import { render, screen, waitFor } from '@testing-library/react';
import { act, render, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

/**
* Internal dependencies
*/
import IsolatedBlockEditor, { CollaborativeEditing } from '../../../../index';
import { getTransports } from '../__test-helpers__/utils';
import { getTransports, pauseTyping } from '../__test-helpers__/utils';

const collabSettings = {
enabled: true,
Expand Down Expand Up @@ -44,9 +44,8 @@ describe( 'CollaborativeEditing: Undo/Redo', () => {
userEvent.keyboard( 'hello' );
expect( screen.getByRole( 'document', { name: 'Paragraph block' } ) ).toHaveTextContent( 'hello' );

// Emulate pause for Yjs to make a new undo stack item
screen.getByRole( 'document', { name: 'Paragraph block' } ).blur();
await waitFor( () => new Promise( ( resolve ) => setTimeout( resolve, 500 ) ) );
await pauseTyping( screen );

userEvent.click( screen.getByRole( 'document', { name: 'Paragraph block' } ) );

userEvent.keyboard( 'world' );
Expand All @@ -73,4 +72,63 @@ describe( 'CollaborativeEditing: Undo/Redo', () => {
userEvent.click( screen.getByRole( 'button', { name: 'Redo' } ) );
expect( screen.getByRole( 'document', { name: 'Paragraph block' } ) ).toHaveTextContent( 'helloworld' );
} );

it( 'should only undo/redo own edits', async () => {
const [ transport1, transport2 ] = getTransports( 2 );
const [ onSave1, onSave2 ] = [ jest.fn(), jest.fn() ];
await act( async () => {
render(
<>
<div data-testid="alice">
<IsolatedBlockEditor settings={ {} } onSaveContent={ onSave1 }>
<CollaborativeEditing
settings={ { ...collabSettings, transport: transport1, username: 'Alice' } }
/>
</IsolatedBlockEditor>
</div>
<div data-testid="bob">
<IsolatedBlockEditor settings={ {} } onSaveContent={ onSave2 }>
<CollaborativeEditing
settings={ { ...collabSettings, transport: transport2, username: 'Bob' } }
/>
</IsolatedBlockEditor>
</div>
</>
);
} );
const aliceScreen = within( screen.getByTestId( 'alice' ) );
const bobScreen = within( screen.getByTestId( 'bob' ) );

userEvent.click( aliceScreen.getByText( /^Start writing.+/ ) );
userEvent.keyboard( 'alice:{Enter}' );

await pauseTyping( aliceScreen );

userEvent.click( bobScreen.getAllByRole( 'document' )[ 1 ] );
userEvent.keyboard( 'bobby:' );

userEvent.click( bobScreen.getByRole( 'button', { name: 'Undo' } ) );
expect( screen.queryByText( 'bobby:' ) ).toBe( null );

userEvent.click( bobScreen.getAllByRole( 'document' )[ 1 ] );
userEvent.keyboard( 'bob:' );

await pauseTyping( bobScreen );

userEvent.click( aliceScreen.getAllByRole( 'document' )[ 0 ] );
userEvent.keyboard( 'hello' );

userEvent.click( bobScreen.getByRole( 'button', { name: 'Undo' } ) );
expect( screen.queryByText( 'bob:' ) ).toBe( null );

expect( screen.getByText( 'alice:hello' ) ).toBeInTheDocument();
userEvent.click( aliceScreen.getByRole( 'button', { name: 'Undo' } ) );
expect( screen.queryByText( 'hello' ) ).toBe( null );

userEvent.click( bobScreen.getByRole( 'button', { name: 'Redo' } ) );
expect( screen.getByText( 'bob:' ) ).toBeInTheDocument();

// Both editors should have the same content
expect( onSave1 ).toHaveBeenLastCalledWith( onSave2.mock.calls[ onSave2.mock.calls.length - 1 ][ 0 ] );
} );
} );

0 comments on commit 7859989

Please sign in to comment.