Skip to content

Commit

Permalink
Refactor tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mirka committed Dec 7, 2021
1 parent 100daa3 commit 230ad88
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 105 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Helper to generate mock transport modules for an isolated channel.
*
* @param {number} count - Number of transport modules to generate.
* @return {Object[]} - Array of transport modules.
*/
export function getTransports( count ) {
const peers = {};

const getAvailablePeers = ( excludeId ) =>
Object.values( peers ).reduce( ( acc, p ) => {
if ( p.user.id === excludeId ) return acc;
return [ ...acc, p.user ];
}, [] );

const mockTransport = () => {
const transport = {
_identity: undefined,
connect: jest.fn( ( { onReceiveMessage, setAvailablePeers, user } ) => {
transport._identity = user.identity;
peers[ user.identity ] = { onReceiveMessage, setAvailablePeers, user: { ...user, id: user.identity } };
Object.keys( peers ).forEach( ( identity ) => {
peers[ identity ].setAvailablePeers( getAvailablePeers( identity ) );
} );
return Promise.resolve( { isFirstInChannel: Object.keys( peers ).length === 1 } );
} ),
sendMessage: jest.fn( ( data ) => {
// console.log( data.message.messageType, data.identity.substring( 0, 4 ) );
Object.keys( peers ).forEach( ( identity ) => {
if ( identity !== data.identity ) {
peers[ identity ].onReceiveMessage( data );
}
} );
} ),
disconnect: jest.fn( () => {
delete peers[ transport._identity ];
Object.keys( peers ).forEach( ( identity ) => {
peers[ identity ].setAvailablePeers( getAvailablePeers( identity ) );
} );
} ),
};

return transport;
};

return Array( count )
.fill( null )
.map( () => mockTransport() );
}
106 changes: 1 addition & 105 deletions src/components/collaborative-editing/use-yjs/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,52 +8,7 @@ import userEvent from '@testing-library/user-event';
* Internal dependencies
*/
import IsolatedBlockEditor, { CollaborativeEditing } from '../../../../index';

/**
* Helper to generate mock transport modules for an isolated channel.
*
* @param {number} count - Number of transport modules to generate.
* @return {Object[]} - Array of transport modules.
*/
function getTransports( count ) {
const peers = {};

const getAvailablePeers = ( excludeId ) =>
Object.values( peers ).reduce( ( acc, p ) => {
if ( p.user.id === excludeId ) return acc;
return [ ...acc, p.user ];
}, [] );

const mockTransport = () => ( {
_identity: undefined,
connect: jest.fn( ( { onReceiveMessage, setAvailablePeers, user } ) => {
mockTransport._identity = user.identity;
peers[ user.identity ] = { onReceiveMessage, setAvailablePeers, user: { ...user, id: user.identity } };
Object.keys( peers ).forEach( ( identity ) => {
peers[ identity ].setAvailablePeers( getAvailablePeers( identity ) );
} );
return Promise.resolve( { isFirstInChannel: Object.keys( peers ).length === 1 } );
} ),
sendMessage: jest.fn( ( data ) => {
// console.log( data.message.messageType, data.identity.substring( 0, 4 ) );
Object.keys( peers ).forEach( ( identity ) => {
if ( identity !== data.identity ) {
peers[ identity ].onReceiveMessage( data );
}
} );
} ),
disconnect: jest.fn( () => {
delete peers[ mockTransport._identity ];
Object.keys( peers ).forEach( ( identity ) => {
peers[ identity ].setAvailablePeers( getAvailablePeers( identity ) );
} );
} ),
} );

return Array( count )
.fill( null )
.map( () => mockTransport() );
}
import { getTransports } from '../__test-helpers__/utils';

const collabSettings = {
enabled: true,
Expand Down Expand Up @@ -211,62 +166,3 @@ describe( 'CollaborativeEditing', () => {
expect( bobScreen.getByRole( 'document', { name: 'Paragraph block' } ) ).toHaveTextContent( 'initialtyped' );
} );
} );

describe( 'CollaborativeEditing: Undo/Redo', () => {
beforeEach( () => {
// Real timers are used so Yjs can merge undo stack items
jest.useRealTimers();
} );

afterEach( () => {
jest.useFakeTimers();
} );

it( 'should undo/redo single user edits', async () => {
const [ transport ] = getTransports( 1 );
const onSave = jest.fn();

render(
<IsolatedBlockEditor settings={ {} } onSaveContent={ onSave }>
<CollaborativeEditing settings={ { ...collabSettings, transport } } />
</IsolatedBlockEditor>
);

expect( screen.getByRole( 'button', { name: 'Undo' } ) ).toHaveAttribute( 'aria-disabled', 'true' );
expect( screen.getByRole( 'button', { name: 'Redo' } ) ).toHaveAttribute( 'aria-disabled', 'true' );

userEvent.click( screen.getByText( /^Start writing.+/ ) );

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 ) ) );
userEvent.click( screen.getByRole( 'document', { name: 'Paragraph block' } ) );

userEvent.keyboard( 'world' );
expect( screen.getByRole( 'document', { name: 'Paragraph block' } ) ).toHaveTextContent( 'helloworld' );

expect( screen.getByRole( 'button', { name: 'Undo' } ) ).toHaveAttribute( 'aria-disabled', 'false' );
userEvent.click( screen.getByRole( 'button', { name: 'Undo' } ) );

expect( screen.getByRole( 'document', { name: 'Paragraph block' } ) ).toHaveTextContent( 'hello' );

expect( screen.getByRole( 'button', { name: 'Undo' } ) ).toHaveAttribute( 'aria-disabled', 'false' );
expect( screen.getByRole( 'button', { name: 'Redo' } ) ).toHaveAttribute( 'aria-disabled', 'false' );
userEvent.click( screen.getByRole( 'button', { name: 'Undo' } ) );

expect( screen.getByText( /^Start writing.+/ ) ).toBeInTheDocument();
expect( onSave ).toHaveBeenLastCalledWith( '' );

expect( screen.getByRole( 'button', { name: 'Undo' } ) ).toHaveAttribute( 'aria-disabled', 'true' );
expect( screen.getByRole( 'button', { name: 'Redo' } ) ).toHaveAttribute( 'aria-disabled', 'false' );

userEvent.click( screen.getByRole( 'button', { name: 'Redo' } ) );
expect( screen.getByRole( 'document', { name: 'Paragraph block' } ) ).toHaveTextContent( 'hello' );

userEvent.click( screen.getByRole( 'button', { name: 'Redo' } ) );
expect( screen.getByRole( 'document', { name: 'Paragraph block' } ) ).toHaveTextContent( 'helloworld' );
} );
} );
76 changes: 76 additions & 0 deletions src/components/collaborative-editing/use-yjs/__tests__/undo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* External dependencies
*/
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

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

const collabSettings = {
enabled: true,
username: 'Peery Peerson',
avatarUrl: 'fake-image.jpg',
};

describe( 'CollaborativeEditing: Undo/Redo', () => {
beforeEach( () => {
// Real timers are used so Yjs can merge undo stack items
jest.useRealTimers();
} );

afterEach( () => {
jest.useFakeTimers();
} );

it( 'should undo/redo single user edits', async () => {
const [ transport ] = getTransports( 1 );
const onSave = jest.fn();

render(
<IsolatedBlockEditor settings={ {} } onSaveContent={ onSave }>
<CollaborativeEditing settings={ { ...collabSettings, transport } } />
</IsolatedBlockEditor>
);

expect( screen.getByRole( 'button', { name: 'Undo' } ) ).toHaveAttribute( 'aria-disabled', 'true' );
expect( screen.getByRole( 'button', { name: 'Redo' } ) ).toHaveAttribute( 'aria-disabled', 'true' );

userEvent.click( screen.getByText( /^Start writing.+/ ) );

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 ) ) );
userEvent.click( screen.getByRole( 'document', { name: 'Paragraph block' } ) );

userEvent.keyboard( 'world' );
expect( screen.getByRole( 'document', { name: 'Paragraph block' } ) ).toHaveTextContent( 'helloworld' );

expect( screen.getByRole( 'button', { name: 'Undo' } ) ).toHaveAttribute( 'aria-disabled', 'false' );
userEvent.click( screen.getByRole( 'button', { name: 'Undo' } ) );

expect( screen.getByRole( 'document', { name: 'Paragraph block' } ) ).toHaveTextContent( 'hello' );

expect( screen.getByRole( 'button', { name: 'Undo' } ) ).toHaveAttribute( 'aria-disabled', 'false' );
expect( screen.getByRole( 'button', { name: 'Redo' } ) ).toHaveAttribute( 'aria-disabled', 'false' );
userEvent.click( screen.getByRole( 'button', { name: 'Undo' } ) );

expect( screen.getByText( /^Start writing.+/ ) ).toBeInTheDocument();
expect( onSave ).toHaveBeenLastCalledWith( '' );

expect( screen.getByRole( 'button', { name: 'Undo' } ) ).toHaveAttribute( 'aria-disabled', 'true' );
expect( screen.getByRole( 'button', { name: 'Redo' } ) ).toHaveAttribute( 'aria-disabled', 'false' );

userEvent.click( screen.getByRole( 'button', { name: 'Redo' } ) );
expect( screen.getByRole( 'document', { name: 'Paragraph block' } ) ).toHaveTextContent( 'hello' );

userEvent.click( screen.getByRole( 'button', { name: 'Redo' } ) );
expect( screen.getByRole( 'document', { name: 'Paragraph block' } ) ).toHaveTextContent( 'helloworld' );
} );
} );

0 comments on commit 230ad88

Please sign in to comment.