@wordpress/block-editor
Version:
1,296 lines (1,158 loc) • 31.2 kB
JavaScript
/**
* External dependencies
*/
import deepFreeze from 'deep-freeze';
/**
* WordPress dependencies
*/
import { createRegistry } from '@wordpress/data';
import {
getBlockTypes,
unregisterBlockType,
registerBlockType,
createBlock,
} from '@wordpress/blocks';
/**
* Internal dependencies
*/
import * as selectors from '../selectors';
import reducer from '../reducer';
import * as actions from '../actions';
import { STORE_NAME as blockEditorStoreName } from '../../store/constants';
const noop = () => {};
const {
clearSelectedBlock,
insertBlock,
insertBlocks,
mergeBlocks,
moveBlocksToPosition,
multiSelect,
removeBlock,
removeBlocks,
replaceBlock,
replaceBlocks,
replaceInnerBlocks,
resetBlocks,
selectBlock,
showInsertionPoint,
startMultiSelect,
startTyping,
stopMultiSelect,
stopTyping,
startDraggingBlocks,
stopDraggingBlocks,
toggleBlockMode,
toggleSelection,
updateBlock,
updateBlockAttributes,
updateBlockListSettings,
updateSettings,
validateBlocksToTemplate,
registerInserterMediaCategory,
setBlockEditingMode,
unsetBlockEditingMode,
} = actions;
describe( 'actions', () => {
const defaultBlockSettings = {
attributes: {
content: {},
},
save: () => 'Saved',
category: 'text',
title: 'block title',
};
describe( 'resetBlocks', () => {
it( 'should dispatch the RESET_BLOCKS action', () => {
const dispatch = jest.fn();
const blocks = [];
resetBlocks( blocks )( { dispatch } );
expect( dispatch ).toHaveBeenCalledWith( {
type: 'RESET_BLOCKS',
blocks,
} );
} );
} );
describe( 'updateBlockAttributes', () => {
it( 'should return the UPDATE_BLOCK_ATTRIBUTES action (string)', () => {
const clientId = 'myclientid';
const attributes = {};
const result = updateBlockAttributes( clientId, attributes );
expect( result ).toEqual( {
type: 'UPDATE_BLOCK_ATTRIBUTES',
clientIds: [ clientId ],
attributes,
uniqueByBlock: false,
} );
} );
it( 'should return the UPDATE_BLOCK_ATTRIBUTES action (array)', () => {
const clientIds = [ 'myclientid' ];
const attributes = {};
const result = updateBlockAttributes( clientIds, attributes );
expect( result ).toEqual( {
type: 'UPDATE_BLOCK_ATTRIBUTES',
clientIds,
attributes,
uniqueByBlock: false,
} );
} );
} );
describe( 'updateBlock', () => {
it( 'should return the UPDATE_BLOCK action', () => {
const clientId = 'myclientid';
const updates = {};
const result = updateBlock( clientId, updates );
expect( result ).toEqual( {
type: 'UPDATE_BLOCK',
clientId,
updates,
} );
} );
} );
describe( 'selectBlock', () => {
it( 'should return the SELECT_BLOCK action', () => {
const clientId = 'myclientid';
const result = selectBlock( clientId, -1 );
expect( result ).toEqual( {
type: 'SELECT_BLOCK',
initialPosition: -1,
clientId,
} );
} );
} );
describe( 'startMultiSelect', () => {
it( 'should return the START_MULTI_SELECT', () => {
expect( startMultiSelect() ).toEqual( {
type: 'START_MULTI_SELECT',
} );
} );
} );
describe( 'stopMultiSelect', () => {
it( 'should return the Stop_MULTI_SELECT', () => {
expect( stopMultiSelect() ).toEqual( {
type: 'STOP_MULTI_SELECT',
} );
} );
} );
describe( 'multiSelect', () => {
it( 'should dispatch MULTI_SELECT action if blocks have the same root client id', () => {
const start = 'start';
const end = 'end';
const select = {
getBlockRootClientId() {
return 'parent'; // For all client IDs.
},
getSelectedBlockCount() {
return 0;
},
};
const dispatch = jest.fn();
multiSelect( start, end )( { select, dispatch } );
expect( dispatch ).toHaveBeenCalledWith( {
type: 'MULTI_SELECT',
start,
end,
initialPosition: 0,
} );
} );
it( 'should do nothing if blocks have different root client ids', () => {
const start = 'start';
const end = 'end';
const select = {
getBlockRootClientId( clientId ) {
switch ( clientId ) {
case start:
return 'parent';
case end:
return 'another parent';
default:
return null;
}
},
getSelectedBlockCount() {
return 0;
},
};
const dispatch = jest.fn();
multiSelect( start, end )( { select, dispatch } );
expect( dispatch ).not.toHaveBeenCalled();
} );
} );
describe( 'clearSelectedBlock', () => {
it( 'should return CLEAR_SELECTED_BLOCK action', () => {
expect( clearSelectedBlock() ).toEqual( {
type: 'CLEAR_SELECTED_BLOCK',
} );
} );
} );
describe( 'replaceBlock', () => {
it( 'should dispatch the REPLACE_BLOCKS action if the new block can be inserted in the destination root block', () => {
const block = {
clientId: 'ribs',
name: 'core/test-block',
};
const select = {
getSettings: () => null,
getBlockRootClientId: () => null,
canInsertBlockType: () => true,
getBlockCount: () => 1,
};
const dispatch = jest.fn();
dispatch.ensureDefaultBlock = jest.fn();
const registry = createRegistry();
replaceBlock( 'chicken', block )( { select, dispatch, registry } );
expect( dispatch ).toHaveBeenCalledWith( {
type: 'REPLACE_BLOCKS',
clientIds: [ 'chicken' ],
blocks: [ block ],
time: expect.any( Number ),
initialPosition: 0,
} );
} );
} );
describe( 'replaceBlocks', () => {
it( 'should not dispatch the REPLACE_BLOCKS action if the replacement is not possible', () => {
const blocks = [
{
clientId: 'ribs',
name: 'core/test-ribs',
},
{
clientId: 'chicken',
name: 'core/test-chicken',
},
];
const select = {
getSettings: () => null,
getBlockRootClientId: () => null,
canInsertBlockType: ( clientId ) => {
switch ( clientId ) {
case 'core/test-ribs':
return true;
case 'core/test-chicken':
default:
return false;
}
},
};
const dispatch = jest.fn();
replaceBlocks( [ 'chicken' ], blocks )( { select, dispatch } );
expect( dispatch ).not.toHaveBeenCalled();
} );
it( 'should dispatch the REPLACE_BLOCKS action if the all the replacement blocks can be inserted in the parent block', () => {
const blocks = [
{
clientId: 'ribs',
name: 'core/test-ribs',
},
{
clientId: 'chicken',
name: 'core/test-chicken',
},
];
const select = {
getSettings: () => null,
getBlockRootClientId: () => null,
canInsertBlockType: () => true,
getBlockCount: () => 1,
};
const dispatch = jest.fn();
dispatch.ensureDefaultBlock = jest.fn();
const registry = createRegistry();
replaceBlocks(
[ 'chicken' ],
blocks
)( { select, dispatch, registry } );
expect( dispatch ).toHaveBeenCalledWith( {
type: 'REPLACE_BLOCKS',
clientIds: [ 'chicken' ],
blocks,
time: expect.any( Number ),
initialPosition: 0,
} );
} );
it( 'should pass patternName through metadata to REPLACE_BLOCKS action', () => {
const blocks = [
{
clientId: 'ribs',
name: 'core/test-ribs',
},
{
clientId: 'chicken',
name: 'core/test-chicken',
},
];
const meta = { patternName: 'core/chicken-ribs-pattern' };
const select = {
getSettings: () => null,
getBlockRootClientId: () => null,
canInsertBlockType: () => true,
getBlockCount: () => 1,
};
const dispatch = jest.fn();
dispatch.ensureDefaultBlock = jest.fn();
const registry = createRegistry();
replaceBlocks(
[ 'chicken' ],
blocks,
null,
null,
meta
)( { select, dispatch, registry } );
expect( dispatch ).toHaveBeenCalledWith( {
type: 'REPLACE_BLOCKS',
clientIds: [ 'chicken' ],
blocks,
time: expect.any( Number ),
indexToSelect: null,
initialPosition: null,
meta: { patternName: 'core/chicken-ribs-pattern' },
} );
} );
} );
describe( 'insertBlock', () => {
it( 'should yield the INSERT_BLOCKS action', () => {
const block = {
clientId: 'ribs',
name: 'core/test-block',
};
const index = 5;
const select = {
getSettings: () => null,
canInsertBlockType: () => true,
};
const dispatch = jest.fn();
insertBlock(
block,
index,
'testclientid',
true
)( { select, dispatch } );
expect( dispatch ).toHaveBeenCalledWith( {
type: 'INSERT_BLOCKS',
blocks: [ block ],
index,
rootClientId: 'testclientid',
time: expect.any( Number ),
updateSelection: true,
initialPosition: 0,
} );
} );
} );
describe( 'insertBlocks', () => {
it( 'should filter the allowed blocks in INSERT_BLOCKS action', () => {
const ribsBlock = {
clientId: 'ribs',
name: 'core/test-ribs',
};
const chickenBlock = {
clientId: 'chicken',
name: 'core/test-chicken',
};
const chickenRibsBlock = {
clientId: 'chicken-ribs',
name: 'core/test-chicken-ribs',
};
const blocks = [ ribsBlock, chickenBlock, chickenRibsBlock ];
const select = {
getSettings: () => null,
canInsertBlockType: ( clientId ) => {
switch ( clientId ) {
case 'core/test-ribs':
return true;
case 'core/test-chicken':
return false;
case 'core/test-chicken-ribs':
return true;
default:
return false;
}
},
};
const dispatch = jest.fn();
insertBlocks(
blocks,
5,
'testrootid',
false
)( { select, dispatch } );
expect( dispatch ).toHaveBeenCalledWith( {
type: 'INSERT_BLOCKS',
blocks: [ ribsBlock, chickenRibsBlock ],
index: 5,
rootClientId: 'testrootid',
time: expect.any( Number ),
updateSelection: false,
initialPosition: null,
} );
} );
it( 'does not dispatch INSERT_BLOCKS action if all the blocks are impossible to insert', () => {
const ribsBlock = {
clientId: 'ribs',
name: 'core/test-ribs',
};
const chickenBlock = {
clientId: 'chicken',
name: 'core/test-chicken',
};
const blocks = [ ribsBlock, chickenBlock ];
const select = {
getSettings: () => null,
canInsertBlockType: () => false,
};
const dispatch = jest.fn();
insertBlocks(
blocks,
5,
'testrootid',
false
)( { select, dispatch } );
expect( dispatch ).not.toHaveBeenCalled();
} );
it( 'should pass patternName through metadata to INSERT_BLOCKS action', () => {
const ribsBlock = {
clientId: 'ribs',
name: 'core/test-ribs',
};
const chickenBlock = {
clientId: 'chicken',
name: 'core/test-chicken',
};
const chickenRibsBlock = {
clientId: 'chicken-ribs',
name: 'core/test-chicken-ribs',
};
const blocks = [ ribsBlock, chickenBlock, chickenRibsBlock ];
const meta = { patternName: 'core/chicken-ribs-pattern' };
const select = {
getSettings: () => null,
canInsertBlockType: ( clientId ) => {
switch ( clientId ) {
case 'core/test-ribs':
return true;
case 'core/test-chicken':
return false;
case 'core/test-chicken-ribs':
return true;
default:
return false;
}
},
};
const dispatch = jest.fn();
insertBlocks(
blocks,
5,
'testrootid',
false,
0,
meta
)( { select, dispatch } );
expect( dispatch ).toHaveBeenCalledWith( {
type: 'INSERT_BLOCKS',
blocks: [ ribsBlock, chickenRibsBlock ],
index: 5,
rootClientId: 'testrootid',
time: expect.any( Number ),
updateSelection: false,
initialPosition: null,
meta: { patternName: 'core/chicken-ribs-pattern' },
} );
} );
} );
describe( 'showInsertionPoint', () => {
it( 'should return the SHOW_INSERTION_POINT action', () => {
expect( showInsertionPoint() ).toEqual( {
type: 'SHOW_INSERTION_POINT',
} );
} );
} );
describe( 'removeBlocks', () => {
it( 'should dispatch REMOVE_BLOCKS action', () => {
const clientId = 'clientId';
const clientIds = [ clientId ];
const select = {
getBlockRootClientId: () => undefined,
canRemoveBlocks: () => true,
getBlockRemovalRules: () => false,
};
const dispatch = Object.assign( jest.fn(), {
selectPreviousBlock: jest.fn(),
} );
const registry = createRegistry();
removeBlocks( clientIds )( { select, dispatch, registry } );
expect( dispatch.selectPreviousBlock ).toHaveBeenCalledWith(
clientId,
true
);
expect( dispatch ).toHaveBeenCalledWith( {
type: 'REMOVE_BLOCKS',
clientIds,
} );
} );
} );
describe( 'moveBlocksToPosition', () => {
it( 'should not dispatch MOVE_BLOCKS_TO_POSITION action if locking is all', () => {
const select = {
canMoveBlocks: () => false,
};
const dispatch = jest.fn();
moveBlocksToPosition(
[ 'chicken' ],
'ribs',
'ribs',
5
)( { select, dispatch } );
expect( dispatch ).not.toHaveBeenCalled();
} );
it( 'should dispatch MOVE_BLOCKS_TO_POSITION action if there is not locking in the original root block and block can be inserted in the destination', () => {
const select = {
canMoveBlocks: () => true,
canRemoveBlocks: () => true,
canInsertBlocks: () => true,
};
const dispatch = jest.fn();
moveBlocksToPosition(
[ 'chicken' ],
'ribs',
'chicken-ribs',
5
)( { select, dispatch } );
expect( dispatch ).toHaveBeenCalledWith( {
type: 'MOVE_BLOCKS_TO_POSITION',
fromRootClientId: 'ribs',
toRootClientId: 'chicken-ribs',
clientIds: [ 'chicken' ],
index: 5,
} );
} );
it( 'should not dispatch MOVE_BLOCKS_TO_POSITION action if there is not locking in the original root block and block can be inserted in the destination', () => {
const select = {
canMoveBlocks: () => true,
canRemoveBlocks: () => true,
canInsertBlocks: () => false,
};
const dispatch = jest.fn();
moveBlocksToPosition(
[ 'chicken' ],
'ribs',
'chicken-ribs',
5
)( { select, dispatch } );
expect( dispatch ).not.toHaveBeenCalled();
} );
} );
describe( 'moveBlockToPosition', () => {
it( 'should dispatch MOVE_BLOCKS_TO_POSITION action with a single block', () => {
const select = {
canMoveBlocks: () => true,
};
const dispatch = jest.fn();
moveBlocksToPosition(
'chicken',
'ribs',
'ribs',
5
)( { select, dispatch } );
expect( dispatch ).toHaveBeenCalledWith( {
type: 'MOVE_BLOCKS_TO_POSITION',
fromRootClientId: 'ribs',
toRootClientId: 'ribs',
clientIds: 'chicken',
index: 5,
} );
} );
} );
describe( 'removeBlock', () => {
it( 'should dispatch REMOVE_BLOCKS action', () => {
const clientId = 'myclientid';
const select = {
getBlockRootClientId: () => null,
canRemoveBlocks: () => true,
getBlockRemovalRules: () => false,
};
const dispatch = Object.assign( jest.fn(), {
selectPreviousBlock: jest.fn(),
} );
const registry = createRegistry();
removeBlock( clientId )( { select, dispatch, registry } );
expect( dispatch.selectPreviousBlock ).toHaveBeenCalledWith(
clientId,
true
);
expect( dispatch ).toHaveBeenCalledWith( {
type: 'REMOVE_BLOCKS',
clientIds: [ clientId ],
} );
} );
it( 'should dispatch REMOVE_BLOCKS action, opting out of select previous', async () => {
const clientId = 'myclientid';
const select = {
getBlockRootClientId: () => null,
canRemoveBlocks: () => true,
getBlockRemovalRules: () => false,
};
const dispatch = Object.assign( jest.fn(), {
selectPreviousBlock: jest.fn(),
} );
const registry = createRegistry();
removeBlocks(
[ clientId ],
false
)( { select, dispatch, registry } );
expect( dispatch.selectPreviousBlock ).not.toHaveBeenCalled();
expect( dispatch ).toHaveBeenCalledWith( {
type: 'REMOVE_BLOCKS',
clientIds: [ clientId ],
} );
} );
} );
describe( 'toggleBlockMode', () => {
it( 'should return TOGGLE_BLOCK_MODE action', () => {
const clientId = 'myclientid';
expect( toggleBlockMode( clientId ) ).toEqual( {
type: 'TOGGLE_BLOCK_MODE',
clientId,
} );
} );
} );
describe( 'startTyping', () => {
it( 'should return the START_TYPING action', () => {
expect( startTyping() ).toEqual( {
type: 'START_TYPING',
} );
} );
} );
describe( 'stopTyping', () => {
it( 'should return the STOP_TYPING action', () => {
expect( stopTyping() ).toEqual( {
type: 'STOP_TYPING',
} );
} );
} );
describe( 'startDraggingBlocks', () => {
it( 'should return the START_DRAGGING_BLOCKS action with the list of clientIds passed', () => {
const clientIds = [ 'block-1', 'block-2', 'block-3' ];
expect( startDraggingBlocks( clientIds ) ).toEqual( {
type: 'START_DRAGGING_BLOCKS',
clientIds,
} );
} );
} );
describe( 'stopDraggingBlocks', () => {
it( 'should return the STOP_DRAGGING_BLOCKS action', () => {
expect( stopDraggingBlocks() ).toEqual( {
type: 'STOP_DRAGGING_BLOCKS',
} );
} );
} );
describe( 'toggleSelection', () => {
it( 'should return the TOGGLE_SELECTION action with default value for isSelectionEnabled = true', () => {
expect( toggleSelection() ).toEqual( {
type: 'TOGGLE_SELECTION',
isSelectionEnabled: true,
} );
} );
it( 'should return the TOGGLE_SELECTION action with isSelectionEnabled = true as passed in the argument', () => {
expect( toggleSelection( true ) ).toEqual( {
type: 'TOGGLE_SELECTION',
isSelectionEnabled: true,
} );
} );
it( 'should return the TOGGLE_SELECTION action with isSelectionEnabled = false as passed in the argument', () => {
expect( toggleSelection( false ) ).toEqual( {
type: 'TOGGLE_SELECTION',
isSelectionEnabled: false,
} );
} );
} );
describe( 'updateBlockListSettings', () => {
it( 'should return the UPDATE_BLOCK_LIST_SETTINGS with undefined settings', () => {
expect( updateBlockListSettings( 'chicken' ) ).toEqual( {
type: 'UPDATE_BLOCK_LIST_SETTINGS',
clientId: 'chicken',
settings: undefined,
} );
} );
it( 'should return the UPDATE_BLOCK_LIST_SETTINGS action with the passed settings', () => {
expect(
updateBlockListSettings( 'chicken', { chicken: 'ribs' } )
).toEqual( {
type: 'UPDATE_BLOCK_LIST_SETTINGS',
clientId: 'chicken',
settings: { chicken: 'ribs' },
} );
} );
} );
describe( 'replaceInnerBlocks', () => {
const block = {
clientId: 'ribs',
};
it( 'should return the REPLACE_INNER_BLOCKS action with default values set', () => {
expect( replaceInnerBlocks( 'root', [ block ] ) ).toEqual( {
type: 'REPLACE_INNER_BLOCKS',
blocks: [ block ],
rootClientId: 'root',
time: expect.any( Number ),
updateSelection: false,
initialPosition: null,
} );
} );
it( 'should return the REPLACE_INNER_BLOCKS action with updateSelection true', () => {
expect( replaceInnerBlocks( 'root', [ block ], true ) ).toEqual( {
type: 'REPLACE_INNER_BLOCKS',
blocks: [ block ],
rootClientId: 'root',
time: expect.any( Number ),
updateSelection: true,
initialPosition: 0,
} );
} );
} );
describe( 'mergeBlocks', () => {
afterEach( () => {
getBlockTypes().forEach( ( block ) => {
unregisterBlockType( block.name );
} );
} );
it( 'should only focus the blockA if the blockA has no merge function', () => {
registerBlockType( 'core/test-block', defaultBlockSettings );
const blockA = deepFreeze( {
clientId: 'chicken',
name: 'core/test-block',
} );
const blockB = deepFreeze( {
clientId: 'ribs',
name: 'core/test-block',
} );
const select = {
getBlock: ( clientId ) =>
[ blockA, blockB ].find( ( b ) => b.clientId === clientId ),
};
const dispatch = Object.assign( jest.fn(), {
selectBlock: jest.fn(),
} );
mergeBlocks(
blockA.clientId,
blockB.clientId
)( { select, dispatch } );
expect( dispatch.selectBlock ).toHaveBeenCalledWith( 'chicken' );
} );
it( 'should merge the blocks if blocks of the same type', () => {
registerBlockType( 'core/test-block', {
attributes: {
content: {},
},
merge( attributes, attributesToMerge ) {
return {
content:
attributes.content +
' ' +
attributesToMerge.content,
};
},
save: noop,
category: 'text',
title: 'test block',
} );
const blockA = deepFreeze( {
clientId: 'chicken',
name: 'core/test-block',
attributes: { content: 'chicken' },
innerBlocks: [],
} );
const blockB = deepFreeze( {
clientId: 'ribs',
name: 'core/test-block',
attributes: { content: 'ribs' },
innerBlocks: [],
} );
const select = {
getBlock: ( clientId ) =>
[ blockA, blockB ].find( ( b ) => b.clientId === clientId ),
getSelectionStart: () => ( {
clientId: blockB.clientId,
attributeKey: 'content',
offset: 0,
} ),
};
const dispatch = Object.assign( jest.fn(), {
replaceBlocks: jest.fn(),
selectionChange: jest.fn(),
} );
mergeBlocks(
blockA.clientId,
blockB.clientId
)( { select, dispatch } );
expect( dispatch.selectionChange ).toHaveBeenCalledWith(
blockA.clientId,
'content',
'chicken'.length + 1,
'chicken'.length + 1
);
expect( dispatch.replaceBlocks ).toHaveBeenCalledWith(
[ 'chicken', 'ribs' ],
[
expect.objectContaining( {
clientId: 'chicken',
name: 'core/test-block',
attributes: { content: 'chicken ribs' },
} ),
],
0
);
} );
it( 'should not merge the blocks have different types without transformation', () => {
registerBlockType( 'core/test-block', {
attributes: {
content: {},
},
merge( attributes, attributesToMerge ) {
return {
content:
attributes.content +
' ' +
attributesToMerge.content,
};
},
save: noop,
category: 'text',
title: 'test block',
} );
registerBlockType( 'core/test-block-2', defaultBlockSettings );
const blockA = deepFreeze( {
clientId: 'chicken',
name: 'core/test-block',
attributes: { content: 'chicken' },
innerBlocks: [],
} );
const blockB = deepFreeze( {
clientId: 'ribs',
name: 'core/test-block-2',
attributes: { content: 'ribs' },
innerBlocks: [],
} );
const select = {
getBlock: ( clientId ) =>
[ blockA, blockB ].find( ( b ) => b.clientId === clientId ),
getSelectionStart: () => ( {
clientId: blockB.clientId,
attributeKey: 'content',
offset: 0,
} ),
};
const dispatch = Object.assign( jest.fn(), {
replaceBlocks: jest.fn(),
} );
mergeBlocks(
blockA.clientId,
blockB.clientId
)( { select, dispatch } );
expect( dispatch.replaceBlocks ).not.toHaveBeenCalled();
} );
it( 'should transform and merge the blocks', () => {
registerBlockType( 'core/test-block', {
attributes: {
content: {
type: 'string',
},
},
merge( attributes, attributesToMerge ) {
return {
content:
attributes.content +
' ' +
attributesToMerge.content,
};
},
save: noop,
category: 'text',
title: 'test block',
} );
registerBlockType( 'core/test-block-2', {
attributes: {
content2: {
type: 'string',
},
},
transforms: {
to: [
{
type: 'block',
blocks: [ 'core/test-block' ],
transform: ( { content2 } ) => {
return createBlock( 'core/test-block', {
content: content2,
} );
},
},
],
},
save: noop,
category: 'text',
title: 'test block 2',
} );
const blockA = deepFreeze( {
clientId: 'chicken',
name: 'core/test-block',
attributes: { content: 'chicken' },
innerBlocks: [],
} );
const blockB = deepFreeze( {
clientId: 'ribs',
name: 'core/test-block-2',
attributes: { content2: 'ribs' },
innerBlocks: [],
} );
const select = {
getBlock: ( clientId ) =>
[ blockA, blockB ].find( ( b ) => b.clientId === clientId ),
getSelectionStart: () => ( {
clientId: blockB.clientId,
attributeKey: 'content2',
offset: 0,
} ),
};
const dispatch = Object.assign( jest.fn(), {
replaceBlocks: jest.fn(),
selectionChange: jest.fn(),
} );
mergeBlocks(
blockA.clientId,
blockB.clientId
)( { select, dispatch } );
expect( dispatch.selectionChange ).toHaveBeenCalledWith(
blockA.clientId,
'content',
'chicken'.length + 1,
'chicken'.length + 1
);
expect( dispatch.replaceBlocks ).toHaveBeenCalledWith(
[ 'chicken', 'ribs' ],
[
expect.objectContaining( {
clientId: 'chicken',
name: 'core/test-block',
attributes: { content: 'chicken ribs' },
} ),
],
0
);
} );
} );
describe( 'validateBlocksToTemplate', () => {
let store;
beforeEach( () => {
store = createRegistry().registerStore( blockEditorStoreName, {
actions,
selectors,
reducer,
} );
registerBlockType( 'core/test-block', defaultBlockSettings );
} );
afterEach( () => {
getBlockTypes().forEach( ( block ) => {
unregisterBlockType( block.name );
} );
} );
it( 'should return undefined if no template assigned', async () => {
const result = await store.dispatch(
validateBlocksToTemplate(
resetBlocks( [ createBlock( 'core/test-block' ) ] ),
store
)
);
expect( result ).toEqual( undefined );
} );
it( 'should return undefined if invalid but unlocked', async () => {
store.dispatch(
updateSettings( {
template: [ [ 'core/foo', {} ] ],
} )
);
const result = await store.dispatch(
validateBlocksToTemplate( [ createBlock( 'core/test-block' ) ] )
);
expect( result ).toEqual( undefined );
} );
it( 'should return undefined if locked and valid', async () => {
store.dispatch(
updateSettings( {
template: [ [ 'core/test-block' ] ],
templateLock: 'all',
} )
);
const result = await store.dispatch(
validateBlocksToTemplate( [ createBlock( 'core/test-block' ) ] )
);
expect( result ).toEqual( undefined );
} );
it( 'should return validity set action if invalid on default state', async () => {
store.dispatch(
updateSettings( {
template: [ [ 'core/foo' ] ],
templateLock: 'all',
} )
);
const result = await store.dispatch(
validateBlocksToTemplate( [ createBlock( 'core/test-block' ) ] )
);
expect( result ).toEqual( false );
} );
} );
describe( 'updateSettings', () => {
it( 'warns when setting the deprecated __unstableIsPreviewMode property and sets the stable property instead', () => {
const consoleWarn = jest
.spyOn( global.console, 'warn' )
.mockImplementation();
const store = createRegistry().registerStore(
blockEditorStoreName,
{
actions,
selectors,
reducer,
}
);
store.dispatch(
updateSettings( {
__unstableIsPreviewMode: true,
} )
);
expect( consoleWarn ).toHaveBeenCalledWith(
"__unstableIsPreviewMode argument in wp.data.dispatch('core/block-editor').updateSettings is deprecated since version 6.8. Please use isPreviewMode instead."
);
consoleWarn.mockClear();
expect( store.getState().settings.__unstableIsPreviewMode ).toBe(
true
);
expect( store.getState().settings.isPreviewMode ).toBe( true );
expect( consoleWarn ).toHaveBeenCalledWith(
'__unstableIsPreviewMode is deprecated since version 6.8. Please use isPreviewMode instead.'
);
consoleWarn.mockRestore();
} );
} );
describe( 'registerInserterMediaCategory', () => {
describe( 'should log errors when invalid', () => {
it( 'valid object', () => {
registerInserterMediaCategory()( {} );
expect( console ).toHaveErroredWith(
'Category should be an `InserterMediaCategory` object.'
);
} );
it( 'has name', () => {
registerInserterMediaCategory( {} )( {} );
expect( console ).toHaveErroredWith(
'Category should have a `name` that should be unique among all media categories.'
);
} );
it( 'has labels.name', () => {
registerInserterMediaCategory( { name: 'a' } )( {} );
expect( console ).toHaveErroredWith(
'Category should have a `labels.name`.'
);
} );
it( 'has proper media type', () => {
registerInserterMediaCategory( {
name: 'a',
labels: { name: 'a' },
mediaType: 'b',
} )( {} );
expect( console ).toHaveErroredWith(
'Category should have `mediaType` property that is one of `image|audio|video`.'
);
} );
it( 'has fetch function', () => {
registerInserterMediaCategory( {
name: 'a',
labels: { name: 'a' },
mediaType: 'image',
fetch: 'c',
} )( {} );
expect( console ).toHaveErroredWith(
'Category should have a `fetch` function defined with the following signature `(InserterMediaRequest) => Promise<InserterMediaItem[]>`.'
);
} );
it( 'has unique name', () => {
registerInserterMediaCategory( {
name: 'a',
labels: { name: 'a' },
mediaType: 'image',
fetch: () => {},
} )( {
select: {
getRegisteredInserterMediaCategories: () => [
{ name: 'a' },
],
},
} );
expect( console ).toHaveErroredWith(
'A category is already registered with the same name: "a".'
);
} );
it( 'has unique labels.name', () => {
registerInserterMediaCategory( {
name: 'a',
labels: { name: 'a' },
mediaType: 'image',
fetch: () => {},
} )( {
select: {
getRegisteredInserterMediaCategories: () => [
{ labels: { name: 'a' } },
],
},
} );
expect( console ).toHaveErroredWith(
'A category is already registered with the same labels.name: "a".'
);
} );
} );
it( 'should register a media category', () => {
const category = {
name: 'new',
labels: { name: 'new' },
mediaType: 'image',
fetch: () => {},
};
const inserterMediaCategories = [
{ name: 'a', labels: { name: 'a' } },
];
const dispatch = jest.fn();
registerInserterMediaCategory( category )( {
select: {
getRegisteredInserterMediaCategories: () =>
inserterMediaCategories,
},
dispatch,
} );
expect( dispatch ).toHaveBeenLastCalledWith( {
type: 'REGISTER_INSERTER_MEDIA_CATEGORY',
category: { ...category, isExternalResource: true },
} );
} );
} );
describe( 'setBlockEditingMode', () => {
it( 'should return the SET_BLOCK_EDITING_MODE action', () => {
expect(
setBlockEditingMode(
'14501cc2-90a6-4f52-aa36-ab6e896135d1',
'default'
)
).toEqual( {
type: 'SET_BLOCK_EDITING_MODE',
clientId: '14501cc2-90a6-4f52-aa36-ab6e896135d1',
mode: 'default',
} );
} );
} );
describe( 'unsetBlockEditingMode', () => {
it( 'should return the UNSET_BLOCK_EDITING_MODE action', () => {
expect(
unsetBlockEditingMode( '14501cc2-90a6-4f52-aa36-ab6e896135d1' )
).toEqual( {
type: 'UNSET_BLOCK_EDITING_MODE',
clientId: '14501cc2-90a6-4f52-aa36-ab6e896135d1',
} );
} );
} );
} );