Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block Directory: Refactor the reducer by breaking out the block management actions into their own reducer. #19330

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 34 additions & 10 deletions packages/block-directory/src/store/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@ import { combineReducers } from '@wordpress/data';
*/
export const downloadableBlocks = ( state = {
results: {},
hasPermission: true,
filterValue: undefined,
isRequestingDownloadableBlocks: true,
installedBlockTypes: [],
}, action ) => {
switch ( action.type ) {
case 'FETCH_DOWNLOADABLE_BLOCKS' :
Expand All @@ -30,21 +28,29 @@ export const downloadableBlocks = ( state = {
results: Object.assign( {}, state.results, {
[ action.filterValue ]: action.downloadableBlocks,
} ),
hasPermission: true,
isRequestingDownloadableBlocks: false,
};
case 'SET_INSTALL_BLOCKS_PERMISSION' :
return {
...state,
items: action.hasPermission ? state.items : [],
hasPermission: action.hasPermission,
};
}
return state;
};

/**
* Reducer managing the installation and deletion of blocks.
*
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
*
* @return {Object} Updated state.
*/
export const blockManagement = ( state = {
installedBlockTypes: [],
}, action ) => {
switch ( action.type ) {
case 'ADD_INSTALLED_BLOCK_TYPE' :
return {
...state,
installedBlockTypes: [ ...state.installedBlockTypes, action.item ],
};

case 'REMOVE_INSTALLED_BLOCK_TYPE' :
return {
...state,
Expand All @@ -54,6 +60,24 @@ export const downloadableBlocks = ( state = {
return state;
};

/**
* Reducer returns whether the user can install blocks.
*
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
*
* @return {Object} Updated state.
*/
export function hasPermission( state = true, action ) {
if ( action.type === 'SET_INSTALL_BLOCKS_PERMISSION' ) {
return action.hasPermission;
}

return state;
}

export default combineReducers( {
downloadableBlocks,
blockManagement,
talldan marked this conversation as resolved.
Show resolved Hide resolved
hasPermission,
} );
9 changes: 2 additions & 7 deletions packages/block-directory/src/store/selectors.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
/**
* External dependencies
*/
import { get } from 'lodash';

/**
* Returns true if application is requesting for downloadable blocks.
*
Expand Down Expand Up @@ -37,7 +32,7 @@ export function getDownloadableBlocks( state, filterValue ) {
* @return {boolean} User has permission to install blocks.
*/
export function hasInstallBlocksPermission( state ) {
return state.downloadableBlocks.hasPermission;
return state.hasPermission;
}

/**
Expand All @@ -48,5 +43,5 @@ export function hasInstallBlocksPermission( state ) {
* @return {Array} Block type items.
*/
export function getInstalledBlockTypes( state ) {
return get( state, [ 'downloadableBlocks', 'installedBlockTypes' ], [] );
return state.blockManagement.installedBlockTypes;
}
23 changes: 23 additions & 0 deletions packages/block-directory/src/store/test/fixtures/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export const downloadableBlock = {
name: 'boxer/boxer',
title: 'Boxer',
description: 'Boxer is a Block that puts your WordPress posts into boxes on a page.',
id: 'boxer-block',
rating: 5,
ratingCount: 1,
activeInstalls: 0,
authorBlockRating: 5,
authorBlockCount: '1',
author: 'CK Lee',
icon: 'block-default',
assets: [
'https://plugins.svn.wordpress.org/boxer-block/trunk/build/index.js',
'https://plugins.svn.wordpress.org/boxer-block/trunk/build/view.js',
],
humanizedUpdated: '3 months ago',
};

export const installedItem = {
id: 'boxer-block',
name: 'boxer/boxer',
};
100 changes: 100 additions & 0 deletions packages/block-directory/src/store/test/reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* External dependencies
*/
import deepFreeze from 'deep-freeze';

/**
* Internal dependencies
*/
import {
downloadableBlocks,
blockManagement,
hasPermission,
} from '../reducer';
import { installedItem, downloadableBlock } from './fixtures';

describe( 'state', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to see these tests!

describe( 'downloadableBlocks()', () => {
it( 'should update state to reflect active search', () => {
const initialState = deepFreeze( {
isRequestingDownloadableBlocks: false,
} );
const state = downloadableBlocks( initialState, {
type: 'FETCH_DOWNLOADABLE_BLOCKS',
} );

expect( state.isRequestingDownloadableBlocks ).toBe( true );
} );

it( 'should update state to reflect search results have returned', () => {
const state = downloadableBlocks( undefined, {
type: 'RECEIVE_DOWNLOADABLE_BLOCKS',
filterValue: downloadableBlock.title,
downloadableBlocks: [ downloadableBlock ],
} );

expect( state.isRequestingDownloadableBlocks ).toBe( false );
} );

it( 'should set user\'s search term and save results', () => {
const state = downloadableBlocks( undefined, {
type: 'RECEIVE_DOWNLOADABLE_BLOCKS',
filterValue: downloadableBlock.title,
downloadableBlocks: [ downloadableBlock ],
} );
expect( state.results ).toHaveProperty( downloadableBlock.title );
expect( state.results[ downloadableBlock.title ] ).toHaveLength( 1 );

// It should append to the results
const updatedState = downloadableBlocks( state, {
type: 'RECEIVE_DOWNLOADABLE_BLOCKS',
filterValue: 'Test 1',
downloadableBlocks: [ downloadableBlock ],
} );

expect( Object.keys( updatedState.results ) ).toHaveLength( 2 );
} );
} );

describe( 'blockManagement()', () => {
it( 'should start with an empty installedBlockTypes List', () => {
const state = blockManagement( undefined, {
type: 'NOOP_TYPE',
} );
expect( state.installedBlockTypes ).toEqual( [] );
} );

it( 'should add item to the installedBlockTypesList', () => {
const initialState = deepFreeze( { installedBlockTypes: [] } );
const state = blockManagement( initialState, {
type: 'ADD_INSTALLED_BLOCK_TYPE',
item: installedItem,
} );

expect( state.installedBlockTypes ).toHaveLength( 1 );
} );

it( 'should remove item from the installedBlockTypesList', () => {
const initialState = deepFreeze( {
installedBlockTypes: [ installedItem ],
} );
const state = blockManagement( initialState, {
type: 'REMOVE_INSTALLED_BLOCK_TYPE',
item: installedItem,
} );

expect( state.installedBlockTypes ).toHaveLength( 0 );
} );
} );

describe( 'hasPermission()', () => {
it( 'should update permissions appropriately', () => {
const state = hasPermission( true, {
type: 'SET_INSTALL_BLOCKS_PERMISSION',
hasPermission: false,
} );

expect( state ).toBe( false );
} );
} );
} );
21 changes: 21 additions & 0 deletions packages/block-directory/src/store/test/selectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Internal dependencies
*/
import {
getInstalledBlockTypes,
} from '../selectors';

describe( 'selectors', () => {
describe( 'getInstalledBlockTypes', () => {
it( 'should retrieve the block types that are installed', () => {
const blockTypes = [ 'fake-type' ];
const state = {
blockManagement: {
installedBlockTypes: blockTypes,
},
};
const installedBlockTypes = getInstalledBlockTypes( state );
expect( installedBlockTypes ).toEqual( blockTypes );
} );
} );
} );