From 33d4261473e329e93b4c732ca91edf860746308c Mon Sep 17 00:00:00 2001 From: Jarda Snajdr Date: Fri, 9 Oct 2020 11:54:14 +0200 Subject: [PATCH 1/2] Editor Actions: fix tests for apiFetch throwing errors --- packages/editor/src/store/test/actions.js | 59 +++++------------------ 1 file changed, 12 insertions(+), 47 deletions(-) diff --git a/packages/editor/src/store/test/actions.js b/packages/editor/src/store/test/actions.js index c7359b90134afd..c49a48e2b6acc2 100644 --- a/packages/editor/src/store/test/actions.js +++ b/packages/editor/src/store/test/actions.js @@ -13,39 +13,6 @@ import { POST_UPDATE_TRANSACTION_ID, } from '../constants'; -jest.mock( '@wordpress/data-controls' ); - -select.mockImplementation( ( ...args ) => { - const { select: actualSelect } = jest.requireActual( - '@wordpress/data-controls' - ); - return actualSelect( ...args ); -} ); - -dispatch.mockImplementation( ( ...args ) => { - const { dispatch: actualDispatch } = jest.requireActual( - '@wordpress/data-controls' - ); - return actualDispatch( ...args ); -} ); - -const apiFetchThrowError = ( error ) => { - apiFetch.mockClear(); - apiFetch.mockImplementation( () => { - throw error; - } ); -}; - -const apiFetchDoActual = () => { - apiFetch.mockClear(); - apiFetch.mockImplementation( ( ...args ) => { - const { apiFetch: fetch } = jest.requireActual( - '@wordpress/data-controls' - ); - return fetch( ...args ); - } ); -}; - const postType = { rest_base: 'posts', labels: { @@ -316,6 +283,7 @@ describe( 'Post generator actions', () => { fulfillment.next( postTypeSlug ); fulfillment.next( postType ); fulfillment.next(); + fulfillment.next( currentPost ); }; it( 'yields expected action for selecting the current post type slug', () => { reset(); @@ -348,11 +316,19 @@ describe( 'Post generator actions', () => { const { value } = fulfillment.next(); expect( value ).toEqual( select( STORE_KEY, 'getCurrentPost' ) ); } ); + it( 'yields expected action object for the api fetch', () => { + const { value } = fulfillment.next( currentPost ); + expect( value ).toEqual( + apiFetch( { + path: `/wp/v2/${ postType.rest_base }/${ currentPost.id }`, + method: 'DELETE', + } ) + ); + } ); describe( 'expected yields when fetch throws an error', () => { it( 'yields expected action for dispatching an error notice', () => { const error = { foo: 'bar', code: 'fail' }; - apiFetchThrowError( error ); - const { value } = fulfillment.next( currentPost ); + const { value } = fulfillment.throw( error ); expect( value ).toEqual( dispatch( 'core/notices', @@ -366,18 +342,8 @@ describe( 'Post generator actions', () => { } ); } ); describe( 'expected yields when fetch does not throw an error', () => { - it( 'yields expected action object for the api fetch', () => { - apiFetchDoActual(); - rewind(); - const { value } = fulfillment.next( currentPost ); - expect( value ).toEqual( - apiFetch( { - path: `/wp/v2/${ postType.rest_base }/${ currentPost.id }`, - method: 'DELETE', - } ) - ); - } ); it( 'yields expected dispatch action for saving the post', () => { + rewind(); const { value } = fulfillment.next(); expect( value ).toEqual( dispatch( STORE_KEY, 'savePost' ) ); } ); @@ -406,7 +372,6 @@ describe( 'Post generator actions', () => { } ); it( 'yields expected action for the api fetch call', () => { const { value } = fulfillment.next( postType ); - apiFetchDoActual(); // since the timestamp is a computed value we can't do a direct comparison. // so we'll just see if the path has most of the value. expect( value.request.path ).toEqual( From c838bdd321be85acd586489e85aa5dfbb119a860 Mon Sep 17 00:00:00 2001 From: Jarda Snajdr Date: Fri, 9 Oct 2020 14:01:42 +0200 Subject: [PATCH 2/2] Migrate the 'editor' package to builtin data controls --- packages/editor/src/store/actions.js | 122 ++++++++++++++-------- packages/editor/src/store/test/actions.js | 63 ++++++----- 2 files changed, 115 insertions(+), 70 deletions(-) diff --git a/packages/editor/src/store/actions.js b/packages/editor/src/store/actions.js index 388368d205b6fa..8c8b4a09067a9b 100644 --- a/packages/editor/src/store/actions.js +++ b/packages/editor/src/store/actions.js @@ -7,12 +7,8 @@ import { has, castArray } from 'lodash'; * WordPress dependencies */ import deprecated from '@wordpress/deprecated'; -import { - dispatch, - select, - syncSelect, - apiFetch, -} from '@wordpress/data-controls'; +import { controls } from '@wordpress/data'; +import { apiFetch } from '@wordpress/data-controls'; import { parse, synchronizeBlocksWithTemplate } from '@wordpress/blocks'; /** @@ -122,8 +118,8 @@ export function* resetAutosave( newAutosave ) { plugin: 'Gutenberg', } ); - const postId = yield select( STORE_KEY, 'getCurrentPostId' ); - yield dispatch( 'core', 'receiveAutosaves', postId, newAutosave ); + const postId = yield controls.select( STORE_KEY, 'getCurrentPostId' ); + yield controls.dispatch( 'core', 'receiveAutosaves', postId, newAutosave ); return { type: '__INERT__' }; } @@ -196,8 +192,8 @@ export function setupEditorState( post ) { * @yield {Object} Action object or control. */ export function* editPost( edits, options ) { - const { id, type } = yield select( STORE_KEY, 'getCurrentPost' ); - yield dispatch( + const { id, type } = yield controls.select( STORE_KEY, 'getCurrentPost' ); + yield controls.dispatch( 'core', 'editEntityRecord', 'postType', @@ -229,21 +225,23 @@ export function __experimentalOptimisticUpdatePost( edits ) { * @param {Object} options */ export function* savePost( options = {} ) { - if ( ! ( yield select( STORE_KEY, 'isEditedPostSaveable' ) ) ) { + if ( ! ( yield controls.select( STORE_KEY, 'isEditedPostSaveable' ) ) ) { return; } let edits = { - content: yield select( STORE_KEY, 'getEditedPostContent' ), + content: yield controls.select( STORE_KEY, 'getEditedPostContent' ), }; if ( ! options.isAutosave ) { - yield dispatch( STORE_KEY, 'editPost', edits, { undoIgnore: true } ); + yield controls.dispatch( STORE_KEY, 'editPost', edits, { + undoIgnore: true, + } ); } yield __experimentalRequestPostUpdateStart( options ); - const previousRecord = yield select( STORE_KEY, 'getCurrentPost' ); + const previousRecord = yield controls.select( STORE_KEY, 'getCurrentPost' ); edits = { id: previousRecord.id, - ...( yield select( + ...( yield controls.select( 'core', 'getEntityRecordNonTransientEdits', 'postType', @@ -252,7 +250,7 @@ export function* savePost( options = {} ) { ) ), ...edits, }; - yield dispatch( + yield controls.dispatch( 'core', 'saveEntityRecord', 'postType', @@ -262,7 +260,7 @@ export function* savePost( options = {} ) { ); yield __experimentalRequestPostUpdateFinish( options ); - const error = yield select( + const error = yield controls.select( 'core', 'getLastEntitySaveError', 'postType', @@ -276,23 +274,38 @@ export function* savePost( options = {} ) { error, } ); if ( args.length ) { - yield dispatch( 'core/notices', 'createErrorNotice', ...args ); + yield controls.dispatch( + 'core/notices', + 'createErrorNotice', + ...args + ); } } else { - const updatedRecord = yield select( STORE_KEY, 'getCurrentPost' ); + const updatedRecord = yield controls.select( + STORE_KEY, + 'getCurrentPost' + ); const args = getNotificationArgumentsForSaveSuccess( { previousPost: previousRecord, post: updatedRecord, - postType: yield select( 'core', 'getPostType', updatedRecord.type ), + postType: yield controls.resolveSelect( + 'core', + 'getPostType', + updatedRecord.type + ), options, } ); if ( args.length ) { - yield dispatch( 'core/notices', 'createSuccessNotice', ...args ); + yield controls.dispatch( + 'core/notices', + 'createSuccessNotice', + ...args + ); } // Make sure that any edits after saving create an undo level and are // considered for change detection. if ( ! options.isAutosave ) { - yield dispatch( + yield controls.dispatch( 'core/block-editor', '__unstableMarkLastChangeAsPersistent' ); @@ -304,9 +317,16 @@ export function* savePost( options = {} ) { * Action generator for handling refreshing the current post. */ export function* refreshPost() { - const post = yield select( STORE_KEY, 'getCurrentPost' ); - const postTypeSlug = yield select( STORE_KEY, 'getCurrentPostType' ); - const postType = yield select( 'core', 'getPostType', postTypeSlug ); + const post = yield controls.select( STORE_KEY, 'getCurrentPost' ); + const postTypeSlug = yield controls.select( + STORE_KEY, + 'getCurrentPostType' + ); + const postType = yield controls.resolveSelect( + 'core', + 'getPostType', + postTypeSlug + ); const newPost = yield apiFetch( { // Timestamp arg allows caller to bypass browser caching, which is // expected for this specific function. @@ -314,26 +334,37 @@ export function* refreshPost() { `/wp/v2/${ postType.rest_base }/${ post.id }` + `?context=edit&_timestamp=${ Date.now() }`, } ); - yield dispatch( STORE_KEY, 'resetPost', newPost ); + yield controls.dispatch( STORE_KEY, 'resetPost', newPost ); } /** * Action generator for trashing the current post in the editor. */ export function* trashPost() { - const postTypeSlug = yield select( STORE_KEY, 'getCurrentPostType' ); - const postType = yield select( 'core', 'getPostType', postTypeSlug ); - yield dispatch( 'core/notices', 'removeNotice', TRASH_POST_NOTICE_ID ); + const postTypeSlug = yield controls.select( + STORE_KEY, + 'getCurrentPostType' + ); + const postType = yield controls.resolveSelect( + 'core', + 'getPostType', + postTypeSlug + ); + yield controls.dispatch( + 'core/notices', + 'removeNotice', + TRASH_POST_NOTICE_ID + ); try { - const post = yield select( STORE_KEY, 'getCurrentPost' ); + const post = yield controls.select( STORE_KEY, 'getCurrentPost' ); yield apiFetch( { path: `/wp/v2/${ postType.rest_base }/${ post.id }`, method: 'DELETE', } ); - yield dispatch( STORE_KEY, 'savePost' ); + yield controls.dispatch( STORE_KEY, 'savePost' ); } catch ( error ) { - yield dispatch( + yield controls.dispatch( 'core/notices', 'createErrorNotice', ...getNotificationArgumentsForTrashFail( { error } ) @@ -351,19 +382,19 @@ export function* trashPost() { */ export function* autosave( { local = false, ...options } = {} ) { if ( local ) { - const post = yield select( STORE_KEY, 'getCurrentPost' ); - const isPostNew = yield select( STORE_KEY, 'isEditedPostNew' ); - const title = yield select( + const post = yield controls.select( STORE_KEY, 'getCurrentPost' ); + const isPostNew = yield controls.select( STORE_KEY, 'isEditedPostNew' ); + const title = yield controls.select( STORE_KEY, 'getEditedPostAttribute', 'title' ); - const content = yield select( + const content = yield controls.select( STORE_KEY, 'getEditedPostAttribute', 'content' ); - const excerpt = yield select( + const excerpt = yield controls.select( STORE_KEY, 'getEditedPostAttribute', 'excerpt' @@ -377,7 +408,7 @@ export function* autosave( { local = false, ...options } = {} ) { excerpt, }; } else { - yield dispatch( STORE_KEY, 'savePost', { + yield controls.dispatch( STORE_KEY, 'savePost', { isAutosave: true, ...options, } ); @@ -391,7 +422,7 @@ export function* autosave( { local = false, ...options } = {} ) { * @yield {Object} Action object. */ export function* redo() { - yield dispatch( 'core', 'redo' ); + yield controls.dispatch( 'core', 'redo' ); } /** @@ -400,7 +431,7 @@ export function* redo() { * @yield {Object} Action object. */ export function* undo() { - yield dispatch( 'core', 'undo' ); + yield controls.dispatch( 'core', 'undo' ); } /** @@ -687,9 +718,12 @@ export function* resetEditorBlocks( blocks, options = {} ) { const edits = { blocks, selectionStart, selectionEnd }; if ( __unstableShouldCreateUndoLevel !== false ) { - const { id, type } = yield select( STORE_KEY, 'getCurrentPost' ); + const { id, type } = yield controls.select( + STORE_KEY, + 'getCurrentPost' + ); const noChange = - ( yield syncSelect( + ( yield controls.select( 'core', 'getEditedEntityRecord', 'postType', @@ -697,7 +731,7 @@ export function* resetEditorBlocks( blocks, options = {} ) { id ) ).blocks === edits.blocks; if ( noChange ) { - return yield dispatch( + return yield controls.dispatch( 'core', '__unstableCreateUndoLevel', 'postType', @@ -739,7 +773,7 @@ const getBlockEditorAction = ( name ) => alternative: "`wp.data.dispatch( 'core/block-editor' )." + name + '`', } ); - yield dispatch( 'core/block-editor', name, ...args ); + yield controls.dispatch( 'core/block-editor', name, ...args ); }; /** diff --git a/packages/editor/src/store/test/actions.js b/packages/editor/src/store/test/actions.js index c49a48e2b6acc2..acf64b8a671518 100644 --- a/packages/editor/src/store/test/actions.js +++ b/packages/editor/src/store/test/actions.js @@ -1,7 +1,8 @@ /** * WordPress dependencies */ -import { select, dispatch, apiFetch } from '@wordpress/data-controls'; +import { apiFetch } from '@wordpress/data-controls'; +import { controls } from '@wordpress/data'; /** * Internal dependencies @@ -46,7 +47,7 @@ describe( 'Post generator actions', () => { reset( isAutosave ); const { value } = fulfillment.next(); expect( value ).toEqual( - select( STORE_KEY, 'isEditedPostSaveable' ) + controls.select( STORE_KEY, 'isEditedPostSaveable' ) ); }, ], @@ -56,7 +57,7 @@ describe( 'Post generator actions', () => { () => { const { value } = fulfillment.next( true ); expect( value ).toEqual( - select( STORE_KEY, 'getEditedPostContent' ) + controls.select( STORE_KEY, 'getEditedPostContent' ) ); }, ], @@ -68,7 +69,7 @@ describe( 'Post generator actions', () => { const edits = { content: currentPost().content }; const { value } = fulfillment.next( edits.content ); expect( value ).toEqual( - dispatch( STORE_KEY, 'editPost', edits, { + controls.dispatch( STORE_KEY, 'editPost', edits, { undoIgnore: true, } ) ); @@ -92,7 +93,7 @@ describe( 'Post generator actions', () => { () => { const { value } = fulfillment.next(); expect( value ).toEqual( - select( STORE_KEY, 'getCurrentPost' ) + controls.select( STORE_KEY, 'getCurrentPost' ) ); }, ], @@ -103,7 +104,7 @@ describe( 'Post generator actions', () => { const post = currentPost(); const { value } = fulfillment.next( post ); expect( value ).toEqual( - select( + controls.select( 'core', 'getEntityRecordNonTransientEdits', 'postType', @@ -120,7 +121,7 @@ describe( 'Post generator actions', () => { const post = currentPost(); const { value } = fulfillment.next( post ); expect( value ).toEqual( - dispatch( + controls.dispatch( 'core', 'saveEntityRecord', 'postType', @@ -151,7 +152,7 @@ describe( 'Post generator actions', () => { const post = currentPost(); const { value } = fulfillment.next(); expect( value ).toEqual( - select( + controls.select( 'core', 'getLastEntitySaveError', 'postType', @@ -167,7 +168,7 @@ describe( 'Post generator actions', () => { () => { const { value } = fulfillment.next(); expect( value ).toEqual( - select( STORE_KEY, 'getCurrentPost' ) + controls.select( STORE_KEY, 'getCurrentPost' ) ); }, ], @@ -178,7 +179,11 @@ describe( 'Post generator actions', () => { const post = currentPost(); const { value } = fulfillment.next( post ); expect( value ).toEqual( - select( 'core', 'getPostType', post.type ) + controls.resolveSelect( + 'core', + 'getPostType', + post.type + ) ); }, ], @@ -189,7 +194,7 @@ describe( 'Post generator actions', () => { if ( ! isAutosave && currentPostStatus === 'publish' ) { const { value } = fulfillment.next( postType ); expect( value ).toEqual( - dispatch( + controls.dispatch( 'core/notices', 'createSuccessNotice', 'Updated Post', @@ -210,7 +215,7 @@ describe( 'Post generator actions', () => { if ( ! isAutosave ) { const { value } = fulfillment.next(); expect( value ).toEqual( - dispatch( + controls.dispatch( 'core/block-editor', '__unstableMarkLastChangeAsPersistent' ) @@ -289,13 +294,13 @@ describe( 'Post generator actions', () => { reset(); const { value } = fulfillment.next(); expect( value ).toEqual( - select( STORE_KEY, 'getCurrentPostType' ) + controls.select( STORE_KEY, 'getCurrentPostType' ) ); } ); it( 'yields expected action for selecting the post type object', () => { const { value } = fulfillment.next( postTypeSlug ); expect( value ).toEqual( - select( 'core', 'getPostType', postTypeSlug ) + controls.resolveSelect( 'core', 'getPostType', postTypeSlug ) ); } ); it( @@ -304,7 +309,7 @@ describe( 'Post generator actions', () => { () => { const { value } = fulfillment.next( postType ); expect( value ).toEqual( - dispatch( + controls.dispatch( 'core/notices', 'removeNotice', TRASH_POST_NOTICE_ID @@ -314,7 +319,9 @@ describe( 'Post generator actions', () => { ); it( 'yields expected action for selecting the currentPost', () => { const { value } = fulfillment.next(); - expect( value ).toEqual( select( STORE_KEY, 'getCurrentPost' ) ); + expect( value ).toEqual( + controls.select( STORE_KEY, 'getCurrentPost' ) + ); } ); it( 'yields expected action object for the api fetch', () => { const { value } = fulfillment.next( currentPost ); @@ -330,7 +337,7 @@ describe( 'Post generator actions', () => { const error = { foo: 'bar', code: 'fail' }; const { value } = fulfillment.throw( error ); expect( value ).toEqual( - dispatch( + controls.dispatch( 'core/notices', 'createErrorNotice', 'Trashing failed', @@ -345,7 +352,9 @@ describe( 'Post generator actions', () => { it( 'yields expected dispatch action for saving the post', () => { rewind(); const { value } = fulfillment.next(); - expect( value ).toEqual( dispatch( STORE_KEY, 'savePost' ) ); + expect( value ).toEqual( + controls.dispatch( STORE_KEY, 'savePost' ) + ); } ); } ); } ); @@ -356,18 +365,20 @@ describe( 'Post generator actions', () => { it( 'yields expected action for selecting the currentPost', () => { reset(); const { value } = fulfillment.next(); - expect( value ).toEqual( select( STORE_KEY, 'getCurrentPost' ) ); + expect( value ).toEqual( + controls.select( STORE_KEY, 'getCurrentPost' ) + ); } ); it( 'yields expected action for selecting the current post type', () => { const { value } = fulfillment.next( currentPost ); expect( value ).toEqual( - select( STORE_KEY, 'getCurrentPostType' ) + controls.select( STORE_KEY, 'getCurrentPostType' ) ); } ); it( 'yields expected action for selecting the post type object', () => { const { value } = fulfillment.next( postTypeSlug ); expect( value ).toEqual( - select( 'core', 'getPostType', postTypeSlug ) + controls.resolveSelect( 'core', 'getPostType', postTypeSlug ) ); } ); it( 'yields expected action for the api fetch call', () => { @@ -383,7 +394,7 @@ describe( 'Post generator actions', () => { it( 'yields expected action for dispatching the reset of the post', () => { const { value } = fulfillment.next( currentPost ); expect( value ).toEqual( - dispatch( STORE_KEY, 'resetPost', currentPost ) + controls.dispatch( STORE_KEY, 'resetPost', currentPost ) ); } ); } ); @@ -464,12 +475,12 @@ describe( 'Editor actions', () => { const fulfillment = actions.editPost( edits ); expect( fulfillment.next() ).toEqual( { done: false, - value: select( STORE_KEY, 'getCurrentPost' ), + value: controls.select( STORE_KEY, 'getCurrentPost' ), } ); const post = { id: 1, type: 'post' }; expect( fulfillment.next( post ) ).toEqual( { done: false, - value: dispatch( + value: controls.dispatch( 'core', 'editEntityRecord', 'postType', @@ -503,7 +514,7 @@ describe( 'Editor actions', () => { const fulfillment = actions.redo(); expect( fulfillment.next() ).toEqual( { done: false, - value: dispatch( 'core', 'redo' ), + value: controls.dispatch( 'core', 'redo' ), } ); expect( fulfillment.next() ).toEqual( { done: true, @@ -517,7 +528,7 @@ describe( 'Editor actions', () => { const fulfillment = actions.undo(); expect( fulfillment.next() ).toEqual( { done: false, - value: dispatch( 'core', 'undo' ), + value: controls.dispatch( 'core', 'undo' ), } ); expect( fulfillment.next() ).toEqual( { done: true,