From d8052367ba84778f4fb79c1b546f68b3a7d5b985 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Mon, 5 Jul 2021 16:13:50 +0200 Subject: [PATCH 01/14] Migrate saveEntityRecord to thunks --- packages/core-data/src/actions.js | 69 ++--- packages/core-data/src/index.js | 1 + packages/core-data/src/test/actions.js | 292 +++++++++--------- .../core-data/src/utils/if-not-resolved.js | 34 +- 4 files changed, 186 insertions(+), 210 deletions(-) diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index 6c3d392c31210b..7a364ef5dd63a6 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -9,6 +9,7 @@ import { v4 as uuid } from 'uuid'; */ import { controls } from '@wordpress/data'; import { apiFetch, __unstableAwaitPromise } from '@wordpress/data-controls'; +import triggerFetch from '@wordpress/api-fetch'; import { addQueryArgs } from '@wordpress/url'; /** @@ -360,13 +361,13 @@ export function __unstableCreateUndoLevel() { * Must return a control * descriptor. */ -export function* saveEntityRecord( +export const saveEntityRecord = ( kind, name, record, { isAutosave = false, __unstableFetch = null } = {} -) { - const entities = yield getKindEntities( kind ); +) => async ( { select, dispatch } ) => { + const entities = await dispatch( getKindEntities( kind ) ); const entity = find( entities, { kind, name } ); if ( ! entity ) { return; @@ -374,10 +375,12 @@ export function* saveEntityRecord( const entityIdKey = entity.key || DEFAULT_ENTITY_KEY; const recordId = record[ entityIdKey ]; - const lock = yield* __unstableAcquireStoreLock( - STORE_NAME, - [ 'entities', 'data', kind, name, recordId || uuid() ], - { exclusive: true } + const lock = await dispatch( + __unstableAcquireStoreLock( + STORE_NAME, + [ 'entities', 'data', kind, name, recordId || uuid() ], + { exclusive: true } + ) ); try { // Evaluate optimized edits. @@ -385,15 +388,9 @@ export function* saveEntityRecord( for ( const [ key, value ] of Object.entries( record ) ) { if ( typeof value === 'function' ) { const evaluatedValue = value( - yield controls.select( - STORE_NAME, - 'getEditedEntityRecord', - kind, - name, - recordId - ) + select.getEditedEntityRecord( kind, name, recordId ) ); - yield editEntityRecord( + await dispatch.editEntityRecord( kind, name, recordId, @@ -406,20 +403,20 @@ export function* saveEntityRecord( } } - yield { + dispatch( { type: 'SAVE_ENTITY_RECORD_START', kind, name, recordId, isAutosave, - }; + } ); let updatedRecord; let error; try { const path = `${ entity.baseURL }${ recordId ? '/' + recordId : '' }`; - const persistedRecord = yield controls.select( + const persistedRecord = select.getRawEntityRecord( STORE_NAME, 'getRawEntityRecord', kind, @@ -432,12 +429,9 @@ export function* saveEntityRecord( // This is fine for now as it is the only supported autosave, // but ideally this should all be handled in the back end, // so the client just sends and receives objects. - const currentUser = yield controls.select( - STORE_NAME, - 'getCurrentUser' - ); + const currentUser = select.getCurrentUser(); const currentUserId = currentUser ? currentUser.id : undefined; - const autosavePost = yield controls.select( + const autosavePost = select.getAutosave( STORE_NAME, 'getAutosave', persistedRecord.type, @@ -472,11 +466,9 @@ export function* saveEntityRecord( data, }; if ( __unstableFetch ) { - updatedRecord = yield __unstableAwaitPromise( - __unstableFetch( options ) - ); + updatedRecord = await __unstableFetch( options ); } else { - updatedRecord = yield apiFetch( options ); + updatedRecord = await triggerFetch( options ); } // An autosave may be processed by the server as a regular save // when its update is requested by the author and the post had @@ -521,7 +513,7 @@ export function* saveEntityRecord( }, {} ); - yield receiveEntityRecords( + await dispatch.receiveEntityRecords( kind, name, newRecord, @@ -529,7 +521,10 @@ export function* saveEntityRecord( true ); } else { - yield receiveAutosaves( persistedRecord.id, updatedRecord ); + await dispatch.receiveAutosaves( + persistedRecord.id, + updatedRecord + ); } } else { let edits = record; @@ -548,13 +543,11 @@ export function* saveEntityRecord( data: edits, }; if ( __unstableFetch ) { - updatedRecord = yield __unstableAwaitPromise( - __unstableFetch( options ) - ); + updatedRecord = await __unstableFetch( options ); } else { - updatedRecord = yield apiFetch( options ); + updatedRecord = await triggerFetch( options ); } - yield receiveEntityRecords( + await dispatch.receiveEntityRecords( kind, name, updatedRecord, @@ -566,20 +559,20 @@ export function* saveEntityRecord( } catch ( _error ) { error = _error; } - yield { + dispatch( { type: 'SAVE_ENTITY_RECORD_FINISH', kind, name, recordId, error, isAutosave, - }; + } ); return updatedRecord; } finally { - yield* __unstableReleaseStoreLock( lock ); + await dispatch( __unstableReleaseStoreLock( lock ) ); } -} +}; /** * Runs multiple core-data actions at the same time using one API request. diff --git a/packages/core-data/src/index.js b/packages/core-data/src/index.js index 4830da46ccc98f..43b9cadb1bc775 100644 --- a/packages/core-data/src/index.js +++ b/packages/core-data/src/index.js @@ -63,6 +63,7 @@ const storeConfig = { actions: { ...actions, ...entityActions, ...locksActions }, selectors: { ...selectors, ...entitySelectors, ...locksSelectors }, resolvers: { ...resolvers, ...entityResolvers }, + __experimentalUseThunks: true, }; /** diff --git a/packages/core-data/src/test/actions.js b/packages/core-data/src/test/actions.js index 6dfec991e2a03d..1f36015e8b03c4 100644 --- a/packages/core-data/src/test/actions.js +++ b/packages/core-data/src/test/actions.js @@ -8,9 +8,9 @@ import { controls } from '@wordpress/data'; */ import { editEntityRecord, - saveEntityRecord, + // saveEntityRecord, deleteEntityRecord, - receiveEntityRecords, + // receiveEntityRecords, receiveUserPermission, receiveAutosaves, receiveCurrentUser, @@ -105,150 +105,150 @@ describe( 'deleteEntityRecord', () => { } ); } ); -describe( 'saveEntityRecord', () => { - it( 'triggers a POST request for a new record', async () => { - const post = { title: 'new post' }; - const entities = [ - { name: 'post', kind: 'postType', baseURL: '/wp/v2/posts' }, - ]; - const fulfillment = saveEntityRecord( 'postType', 'post', post ); - // Trigger generator - fulfillment.next(); - - // Provide entities and acquire lock - expect( fulfillment.next( entities ).value.type ).toBe( - 'MOCKED_ACQUIRE_LOCK' - ); - - // Trigger apiFetch - expect( fulfillment.next().value.type ).toEqual( - 'SAVE_ENTITY_RECORD_START' - ); - - expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' ); - const { value: apiFetchAction } = fulfillment.next( {} ); - expect( apiFetchAction.request ).toEqual( { - path: '/wp/v2/posts', - method: 'POST', - data: post, - } ); - // Provide response and trigger action - const updatedRecord = { ...post, id: 10 }; - const { value: received } = fulfillment.next( updatedRecord ); - expect( received ).toEqual( - receiveEntityRecords( - 'postType', - 'post', - updatedRecord, - undefined, - true, - { title: 'new post' } - ) - ); - expect( fulfillment.next().value.type ).toBe( - 'SAVE_ENTITY_RECORD_FINISH' - ); - // Release lock - expect( fulfillment.next().value.type ).toEqual( - 'MOCKED_RELEASE_LOCK' - ); - - expect( fulfillment.next().value ).toBe( updatedRecord ); - } ); - - it( 'triggers a PUT request for an existing record', async () => { - const post = { id: 10, title: 'new post' }; - const entities = [ - { name: 'post', kind: 'postType', baseURL: '/wp/v2/posts' }, - ]; - const fulfillment = saveEntityRecord( 'postType', 'post', post ); - // Trigger generator - fulfillment.next(); - - // Provide entities and acquire lock - expect( fulfillment.next( entities ).value.type ).toBe( - 'MOCKED_ACQUIRE_LOCK' - ); - - // Trigger apiFetch - expect( fulfillment.next().value.type ).toEqual( - 'SAVE_ENTITY_RECORD_START' - ); - expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' ); - const { value: apiFetchAction } = fulfillment.next( {} ); - expect( apiFetchAction.request ).toEqual( { - path: '/wp/v2/posts/10', - method: 'PUT', - data: post, - } ); - // Provide response and trigger action - const { value: received } = fulfillment.next( post ); - expect( received ).toEqual( - receiveEntityRecords( 'postType', 'post', post, undefined, true, { - title: 'new post', - id: 10, - } ) - ); - expect( fulfillment.next().value.type ).toBe( - 'SAVE_ENTITY_RECORD_FINISH' - ); - // Release lock - expect( fulfillment.next().value.type ).toEqual( - 'MOCKED_RELEASE_LOCK' - ); - } ); - - it( 'triggers a PUT request for an existing record with a custom key', async () => { - const postType = { slug: 'page', title: 'Pages' }; - const entities = [ - { - name: 'postType', - kind: 'root', - baseURL: '/wp/v2/types', - key: 'slug', - }, - ]; - const fulfillment = saveEntityRecord( 'root', 'postType', postType ); - // Trigger generator - fulfillment.next(); - - // Provide entities and acquire lock - expect( fulfillment.next( entities ).value.type ).toBe( - 'MOCKED_ACQUIRE_LOCK' - ); - - // Trigger apiFetch - expect( fulfillment.next().value.type ).toEqual( - 'SAVE_ENTITY_RECORD_START' - ); - expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' ); - const { value: apiFetchAction } = fulfillment.next( {} ); - expect( apiFetchAction.request ).toEqual( { - path: '/wp/v2/types/page', - method: 'PUT', - data: postType, - } ); - // Provide response and trigger action - const { value: received } = fulfillment.next( postType ); - expect( received ).toEqual( - receiveEntityRecords( - 'root', - 'postType', - postType, - undefined, - true, - { slug: 'page', title: 'Pages' } - ) - ); - expect( fulfillment.next().value.type ).toBe( - 'SAVE_ENTITY_RECORD_FINISH' - ); - // Release lock - expect( fulfillment.next().value.type ).toEqual( - 'MOCKED_RELEASE_LOCK' - ); - } ); -} ); +// describe( 'saveEntityRecord', () => { +// it( 'triggers a POST request for a new record', async () => { +// const post = { title: 'new post' }; +// const entities = [ +// { name: 'post', kind: 'postType', baseURL: '/wp/v2/posts' }, +// ]; +// const fulfillment = saveEntityRecord( 'postType', 'post', post ); +// // Trigger generator +// fulfillment.next(); +// +// // Provide entities and acquire lock +// expect( fulfillment.next( entities ).value.type ).toBe( +// 'MOCKED_ACQUIRE_LOCK' +// ); +// +// // Trigger apiFetch +// expect( fulfillment.next().value.type ).toEqual( +// 'SAVE_ENTITY_RECORD_START' +// ); +// +// expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' ); +// const { value: apiFetchAction } = fulfillment.next( {} ); +// expect( apiFetchAction.request ).toEqual( { +// path: '/wp/v2/posts', +// method: 'POST', +// data: post, +// } ); +// // Provide response and trigger action +// const updatedRecord = { ...post, id: 10 }; +// const { value: received } = fulfillment.next( updatedRecord ); +// expect( received ).toEqual( +// receiveEntityRecords( +// 'postType', +// 'post', +// updatedRecord, +// undefined, +// true, +// { title: 'new post' } +// ) +// ); +// expect( fulfillment.next().value.type ).toBe( +// 'SAVE_ENTITY_RECORD_FINISH' +// ); +// // Release lock +// expect( fulfillment.next().value.type ).toEqual( +// 'MOCKED_RELEASE_LOCK' +// ); +// +// expect( fulfillment.next().value ).toBe( updatedRecord ); +// } ); +// +// it( 'triggers a PUT request for an existing record', async () => { +// const post = { id: 10, title: 'new post' }; +// const entities = [ +// { name: 'post', kind: 'postType', baseURL: '/wp/v2/posts' }, +// ]; +// const fulfillment = saveEntityRecord( 'postType', 'post', post ); +// // Trigger generator +// fulfillment.next(); +// +// // Provide entities and acquire lock +// expect( fulfillment.next( entities ).value.type ).toBe( +// 'MOCKED_ACQUIRE_LOCK' +// ); +// +// // Trigger apiFetch +// expect( fulfillment.next().value.type ).toEqual( +// 'SAVE_ENTITY_RECORD_START' +// ); +// expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' ); +// const { value: apiFetchAction } = fulfillment.next( {} ); +// expect( apiFetchAction.request ).toEqual( { +// path: '/wp/v2/posts/10', +// method: 'PUT', +// data: post, +// } ); +// // Provide response and trigger action +// const { value: received } = fulfillment.next( post ); +// expect( received ).toEqual( +// receiveEntityRecords( 'postType', 'post', post, undefined, true, { +// title: 'new post', +// id: 10, +// } ) +// ); +// expect( fulfillment.next().value.type ).toBe( +// 'SAVE_ENTITY_RECORD_FINISH' +// ); +// // Release lock +// expect( fulfillment.next().value.type ).toEqual( +// 'MOCKED_RELEASE_LOCK' +// ); +// } ); +// +// it( 'triggers a PUT request for an existing record with a custom key', async () => { +// const postType = { slug: 'page', title: 'Pages' }; +// const entities = [ +// { +// name: 'postType', +// kind: 'root', +// baseURL: '/wp/v2/types', +// key: 'slug', +// }, +// ]; +// const fulfillment = saveEntityRecord( 'root', 'postType', postType ); +// // Trigger generator +// fulfillment.next(); +// +// // Provide entities and acquire lock +// expect( fulfillment.next( entities ).value.type ).toBe( +// 'MOCKED_ACQUIRE_LOCK' +// ); +// +// // Trigger apiFetch +// expect( fulfillment.next().value.type ).toEqual( +// 'SAVE_ENTITY_RECORD_START' +// ); +// expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' ); +// const { value: apiFetchAction } = fulfillment.next( {} ); +// expect( apiFetchAction.request ).toEqual( { +// path: '/wp/v2/types/page', +// method: 'PUT', +// data: postType, +// } ); +// // Provide response and trigger action +// const { value: received } = fulfillment.next( postType ); +// expect( received ).toEqual( +// receiveEntityRecords( +// 'root', +// 'postType', +// postType, +// undefined, +// true, +// { slug: 'page', title: 'Pages' } +// ) +// ); +// expect( fulfillment.next().value.type ).toBe( +// 'SAVE_ENTITY_RECORD_FINISH' +// ); +// // Release lock +// expect( fulfillment.next().value.type ).toEqual( +// 'MOCKED_RELEASE_LOCK' +// ); +// } ); +// } ); describe( 'receiveUserPermission', () => { it( 'builds an action object', () => { diff --git a/packages/core-data/src/utils/if-not-resolved.js b/packages/core-data/src/utils/if-not-resolved.js index 0baf36f0e5d8d9..56b48d011157ca 100644 --- a/packages/core-data/src/utils/if-not-resolved.js +++ b/packages/core-data/src/utils/if-not-resolved.js @@ -1,13 +1,3 @@ -/** - * WordPress dependencies - */ -import { controls } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import { STORE_NAME } from '../name'; - /** * Higher-order function which invokes the given resolver only if it has not * already been resolved with the arguments passed to the enhanced function. @@ -20,21 +10,13 @@ import { STORE_NAME } from '../name'; * * @return {Function} Enhanced resolver. */ -const ifNotResolved = ( resolver, selectorName ) => - /** - * @param {...any} args Original resolver arguments. - */ - function* resolveIfNotResolved( ...args ) { - const hasStartedResolution = yield controls.select( - STORE_NAME, - 'hasStartedResolution', - selectorName, - args - ); - - if ( ! hasStartedResolution ) { - yield* resolver( ...args ); - } - }; +const ifNotResolved = ( resolver, selectorName ) => ( ...args ) => ( { + select, + dispatch, +} ) => { + if ( ! select.hasStartedResolution( selectorName, args ) ) { + dispatch( resolver( ...args ) ); + } +}; export default ifNotResolved; From d227a799ac873d204c9262d446ba79dd883782b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Wed, 25 Aug 2021 13:58:07 +0200 Subject: [PATCH 02/14] Adjust ifNotResolved tests --- .../src/utils/test/if-not-resolved.js | 38 +++++-------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/packages/core-data/src/utils/test/if-not-resolved.js b/packages/core-data/src/utils/test/if-not-resolved.js index a773097d70514f..eab3b04680065f 100644 --- a/packages/core-data/src/utils/test/if-not-resolved.js +++ b/packages/core-data/src/utils/test/if-not-resolved.js @@ -27,48 +27,30 @@ describe( 'ifNotResolved', () => { expect( resolver ).toBeInstanceOf( Function ); } ); - it( 'triggers original resolver if not already resolved', () => { - controls.select.mockImplementation( ( _storeKey, selectorName ) => ( { - _nextValue: - selectorName === 'hasStartedResolution' ? false : undefined, - } ) ); + it( 'triggers original resolver if not already resolved', async () => { + const select = { hasStartedResolution: () => false }; + const dispatch = () => {}; const originalResolver = jest .fn() - .mockImplementation( function* () {} ); + .mockImplementation( async function () {} ); const resolver = ifNotResolved( originalResolver, 'originalResolver' ); - - const runResolver = resolver(); - - let next, nextValue; - do { - next = runResolver.next( nextValue ); - nextValue = next.value?._nextValue; - } while ( ! next.done ); + await resolver()( { select, dispatch } ); expect( originalResolver ).toHaveBeenCalledTimes( 1 ); } ); - it( 'does not trigger original resolver if already resolved', () => { - controls.select.mockImplementation( ( _storeKey, selectorName ) => ( { - _nextValue: - selectorName === 'hasStartedResolution' ? true : undefined, - } ) ); + it( 'does not trigger original resolver if already resolved', async () => { + const select = { hasStartedResolution: () => true }; + const dispatch = () => {}; const originalResolver = jest .fn() - .mockImplementation( function* () {} ); + .mockImplementation( async function () {} ); const resolver = ifNotResolved( originalResolver, 'originalResolver' ); - - const runResolver = resolver(); - - let next, nextValue; - do { - next = runResolver.next( nextValue ); - nextValue = next.value?._nextValue; - } while ( ! next.done ); + await resolver()( { select, dispatch } ); expect( originalResolver ).toHaveBeenCalledTimes( 0 ); } ); From 7a9bd07615ef4d7dc3dbe56bf2635d733a46761b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Wed, 25 Aug 2021 14:03:06 +0200 Subject: [PATCH 03/14] Adjust the integration tests --- packages/core-data/src/test/integration.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/core-data/src/test/integration.js b/packages/core-data/src/test/integration.js index 43fbdaeb27bd97..6eb1645c506fc7 100644 --- a/packages/core-data/src/test/integration.js +++ b/packages/core-data/src/test/integration.js @@ -213,6 +213,11 @@ describe( 'saveEntityRecord', () => { slug: 'post-1', newField: 'a', } ); + + // Wait a few ticks – without rungen we have less control over the flow of things. + // @TODO: A better solution + await runPendingPromises(); + await runPendingPromises(); await runPendingPromises(); // There should ONLY be a single hanging API call (PUT) by this point. From f0b22c0ef848a97a3ff2fb0c9183c56022413991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Wed, 25 Aug 2021 16:10:01 +0200 Subject: [PATCH 04/14] Adjust args to select() --- packages/core-data/src/actions.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index 7a364ef5dd63a6..786b2a594d3d9c 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -403,7 +403,7 @@ export const saveEntityRecord = ( } } - dispatch( { + await dispatch( { type: 'SAVE_ENTITY_RECORD_START', kind, name, @@ -417,8 +417,6 @@ export const saveEntityRecord = ( recordId ? '/' + recordId : '' }`; const persistedRecord = select.getRawEntityRecord( - STORE_NAME, - 'getRawEntityRecord', kind, name, recordId @@ -432,8 +430,6 @@ export const saveEntityRecord = ( const currentUser = select.getCurrentUser(); const currentUserId = currentUser ? currentUser.id : undefined; const autosavePost = select.getAutosave( - STORE_NAME, - 'getAutosave', persistedRecord.type, persistedRecord.id, currentUserId From 21410ba46fc8c880ccdb25238f315f4ea7b5bc70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Wed, 25 Aug 2021 17:17:16 +0200 Subject: [PATCH 05/14] Refactor functions depending on saveEditedEntityRecord to thunks --- packages/core-data/src/actions.js | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index 786b2a594d3d9c..6f5c9e037e5b07 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -647,11 +647,10 @@ export function* __experimentalBatch( requests ) { * @param {Object} recordId ID of the record. * @param {Object} options Saving options. */ -export function* saveEditedEntityRecord( kind, name, recordId, options ) { +export const saveEditedEntityRecord = ( kind, name, recordId, options ) => + async ( { select, dispatch } ) => { if ( - ! ( yield controls.select( - STORE_NAME, - 'hasEditsForEntityRecord', + ! ( select.hasEditsForEntityRecord( kind, name, recordId @@ -659,15 +658,13 @@ export function* saveEditedEntityRecord( kind, name, recordId, options ) { ) { return; } - const edits = yield controls.select( - STORE_NAME, - 'getEntityRecordNonTransientEdits', + const edits = select.getEntityRecordNonTransientEdits( kind, name, recordId ); const record = { id: recordId, ...edits }; - return yield* saveEntityRecord( kind, name, record, options ); + return await dispatch( saveEntityRecord( kind, name, record, options ) ); } /** @@ -679,17 +676,15 @@ export function* saveEditedEntityRecord( kind, name, recordId, options ) { * @param {Array} itemsToSave List of entity properties to save. * @param {Object} options Saving options. */ -export function* __experimentalSaveSpecifiedEntityEdits( +export const __experimentalSaveSpecifiedEntityEdits = ( kind, name, recordId, itemsToSave, options -) { +) => async ( { select, dispatch } ) => { if ( - ! ( yield controls.select( - STORE_NAME, - 'hasEditsForEntityRecord', + ! ( select.hasEditsForEntityRecord( kind, name, recordId @@ -697,9 +692,7 @@ export function* __experimentalSaveSpecifiedEntityEdits( ) { return; } - const edits = yield controls.select( - STORE_NAME, - 'getEntityRecordNonTransientEdits', + const edits = select.getEntityRecordNonTransientEdits( kind, name, recordId @@ -710,7 +703,7 @@ export function* __experimentalSaveSpecifiedEntityEdits( editsToSave[ edit ] = edits[ edit ]; } } - return yield* saveEntityRecord( kind, name, editsToSave, options ); + return await dispatch( saveEntityRecord( kind, name, editsToSave, options ) ); } /** From 65f3e56ef93c986db64e66e5e404ad0e6ce0b045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Wed, 25 Aug 2021 17:18:06 +0200 Subject: [PATCH 06/14] Lint --- packages/core-data/src/actions.js | 32 +++++++++++++------------------ 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index 6f5c9e037e5b07..f292771f38aca0 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -647,15 +647,13 @@ export function* __experimentalBatch( requests ) { * @param {Object} recordId ID of the record. * @param {Object} options Saving options. */ -export const saveEditedEntityRecord = ( kind, name, recordId, options ) => - async ( { select, dispatch } ) => { - if ( - ! ( select.hasEditsForEntityRecord( - kind, - name, - recordId - ) ) - ) { +export const saveEditedEntityRecord = ( + kind, + name, + recordId, + options +) => async ( { select, dispatch } ) => { + if ( ! select.hasEditsForEntityRecord( kind, name, recordId ) ) { return; } const edits = select.getEntityRecordNonTransientEdits( @@ -665,7 +663,7 @@ export const saveEditedEntityRecord = ( kind, name, recordId, options ) => ); const record = { id: recordId, ...edits }; return await dispatch( saveEntityRecord( kind, name, record, options ) ); -} +}; /** * Action triggered to save only specified properties for the entity. @@ -683,13 +681,7 @@ export const __experimentalSaveSpecifiedEntityEdits = ( itemsToSave, options ) => async ( { select, dispatch } ) => { - if ( - ! ( select.hasEditsForEntityRecord( - kind, - name, - recordId - ) ) - ) { + if ( ! select.hasEditsForEntityRecord( kind, name, recordId ) ) { return; } const edits = select.getEntityRecordNonTransientEdits( @@ -703,8 +695,10 @@ export const __experimentalSaveSpecifiedEntityEdits = ( editsToSave[ edit ] = edits[ edit ]; } } - return await dispatch( saveEntityRecord( kind, name, editsToSave, options ) ); -} + return await dispatch( + saveEntityRecord( kind, name, editsToSave, options ) + ); +}; /** * Returns an action object used in signalling that Upload permissions have been received. From f244c9614cbcfb2bf48d219ea2fd8244f33e0930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Thu, 26 Aug 2021 14:01:22 +0200 Subject: [PATCH 07/14] Adjust saveEntityRecord to deal with async calls instead of generators --- packages/core-data/src/test/actions.js | 379 +++++++++++++++---------- 1 file changed, 234 insertions(+), 145 deletions(-) diff --git a/packages/core-data/src/test/actions.js b/packages/core-data/src/test/actions.js index 1f36015e8b03c4..11c5cb4f6d23f1 100644 --- a/packages/core-data/src/test/actions.js +++ b/packages/core-data/src/test/actions.js @@ -2,13 +2,16 @@ * WordPress dependencies */ import { controls } from '@wordpress/data'; +import apiFetch from '@wordpress/api-fetch'; + +jest.mock( '@wordpress/api-fetch' ); /** * Internal dependencies */ import { editEntityRecord, - // saveEntityRecord, + saveEntityRecord, deleteEntityRecord, // receiveEntityRecords, receiveUserPermission, @@ -105,150 +108,236 @@ describe( 'deleteEntityRecord', () => { } ); } ); -// describe( 'saveEntityRecord', () => { -// it( 'triggers a POST request for a new record', async () => { -// const post = { title: 'new post' }; -// const entities = [ -// { name: 'post', kind: 'postType', baseURL: '/wp/v2/posts' }, -// ]; -// const fulfillment = saveEntityRecord( 'postType', 'post', post ); -// // Trigger generator -// fulfillment.next(); -// -// // Provide entities and acquire lock -// expect( fulfillment.next( entities ).value.type ).toBe( -// 'MOCKED_ACQUIRE_LOCK' -// ); -// -// // Trigger apiFetch -// expect( fulfillment.next().value.type ).toEqual( -// 'SAVE_ENTITY_RECORD_START' -// ); -// -// expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' ); -// const { value: apiFetchAction } = fulfillment.next( {} ); -// expect( apiFetchAction.request ).toEqual( { -// path: '/wp/v2/posts', -// method: 'POST', -// data: post, -// } ); -// // Provide response and trigger action -// const updatedRecord = { ...post, id: 10 }; -// const { value: received } = fulfillment.next( updatedRecord ); -// expect( received ).toEqual( -// receiveEntityRecords( -// 'postType', -// 'post', -// updatedRecord, -// undefined, -// true, -// { title: 'new post' } -// ) -// ); -// expect( fulfillment.next().value.type ).toBe( -// 'SAVE_ENTITY_RECORD_FINISH' -// ); -// // Release lock -// expect( fulfillment.next().value.type ).toEqual( -// 'MOCKED_RELEASE_LOCK' -// ); -// -// expect( fulfillment.next().value ).toBe( updatedRecord ); -// } ); -// -// it( 'triggers a PUT request for an existing record', async () => { -// const post = { id: 10, title: 'new post' }; -// const entities = [ -// { name: 'post', kind: 'postType', baseURL: '/wp/v2/posts' }, -// ]; -// const fulfillment = saveEntityRecord( 'postType', 'post', post ); -// // Trigger generator -// fulfillment.next(); -// -// // Provide entities and acquire lock -// expect( fulfillment.next( entities ).value.type ).toBe( -// 'MOCKED_ACQUIRE_LOCK' -// ); -// -// // Trigger apiFetch -// expect( fulfillment.next().value.type ).toEqual( -// 'SAVE_ENTITY_RECORD_START' -// ); -// expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' ); -// const { value: apiFetchAction } = fulfillment.next( {} ); -// expect( apiFetchAction.request ).toEqual( { -// path: '/wp/v2/posts/10', -// method: 'PUT', -// data: post, -// } ); -// // Provide response and trigger action -// const { value: received } = fulfillment.next( post ); -// expect( received ).toEqual( -// receiveEntityRecords( 'postType', 'post', post, undefined, true, { -// title: 'new post', -// id: 10, -// } ) -// ); -// expect( fulfillment.next().value.type ).toBe( -// 'SAVE_ENTITY_RECORD_FINISH' -// ); -// // Release lock -// expect( fulfillment.next().value.type ).toEqual( -// 'MOCKED_RELEASE_LOCK' -// ); -// } ); -// -// it( 'triggers a PUT request for an existing record with a custom key', async () => { -// const postType = { slug: 'page', title: 'Pages' }; -// const entities = [ -// { -// name: 'postType', -// kind: 'root', -// baseURL: '/wp/v2/types', -// key: 'slug', -// }, -// ]; -// const fulfillment = saveEntityRecord( 'root', 'postType', postType ); -// // Trigger generator -// fulfillment.next(); -// -// // Provide entities and acquire lock -// expect( fulfillment.next( entities ).value.type ).toBe( -// 'MOCKED_ACQUIRE_LOCK' -// ); -// -// // Trigger apiFetch -// expect( fulfillment.next().value.type ).toEqual( -// 'SAVE_ENTITY_RECORD_START' -// ); -// expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' ); -// const { value: apiFetchAction } = fulfillment.next( {} ); -// expect( apiFetchAction.request ).toEqual( { -// path: '/wp/v2/types/page', -// method: 'PUT', -// data: postType, -// } ); -// // Provide response and trigger action -// const { value: received } = fulfillment.next( postType ); -// expect( received ).toEqual( -// receiveEntityRecords( -// 'root', -// 'postType', -// postType, -// undefined, -// true, -// { slug: 'page', title: 'Pages' } -// ) -// ); -// expect( fulfillment.next().value.type ).toBe( -// 'SAVE_ENTITY_RECORD_FINISH' -// ); -// // Release lock -// expect( fulfillment.next().value.type ).toEqual( -// 'MOCKED_RELEASE_LOCK' -// ); -// } ); -// } ); +describe( 'saveEntityRecord', () => { + beforeEach( async () => { + apiFetch.mockReset(); + jest.useFakeTimers(); + } ); + + it( 'triggers a POST request for a new record', async () => { + const post = { title: 'new post' }; + const entities = [ + { name: 'post', kind: 'postType', baseURL: '/wp/v2/posts' }, + ]; + const select = { + getRawEntityRecord: () => post, + }; + + const dispatch = Object.assign( jest.fn(), { + receiveEntityRecords: jest.fn(), + } ); + // Provide entities + dispatch.mockReturnValueOnce( entities ); + + // Provide response + const updatedRecord = { ...post, id: 10 }; + apiFetch.mockImplementation( () => { + return updatedRecord; + } ); + + const result = await saveEntityRecord( + 'postType', + 'post', + post + )( { select, dispatch } ); + + expect( apiFetch ).toHaveBeenCalledTimes( 1 ); + expect( apiFetch ).toHaveBeenCalledWith( { + path: '/wp/v2/posts', + method: 'POST', + data: post, + } ); + + expect( dispatch ).toHaveBeenCalledTimes( 5 ); + expect( dispatch ).toHaveBeenCalledWith( { + type: 'SAVE_ENTITY_RECORD_START', + kind: 'postType', + name: 'post', + recordId: undefined, + isAutosave: false, + } ); + expect( dispatch ).toHaveBeenCalledWith( [ + { + type: 'MOCKED_ACQUIRE_LOCK', + }, + ] ); + expect( dispatch ).toHaveBeenCalledWith( { + type: 'SAVE_ENTITY_RECORD_FINISH', + kind: 'postType', + name: 'post', + recordId: undefined, + error: undefined, + isAutosave: false, + } ); + expect( dispatch ).toHaveBeenCalledWith( [ + { + type: 'MOCKED_RELEASE_LOCK', + }, + ] ); + + expect( dispatch.receiveEntityRecords ).toHaveBeenCalledTimes( 1 ); + expect( dispatch.receiveEntityRecords ).toHaveBeenCalledWith( + 'postType', + 'post', + updatedRecord, + undefined, + true, + post + ); + + expect( result ).toBe( updatedRecord ); + } ); + + it( 'triggers a PUT request for an existing record', async () => { + const post = { id: 10, title: 'new post' }; + const entities = [ + { name: 'post', kind: 'postType', baseURL: '/wp/v2/posts' }, + ]; + const select = { + getRawEntityRecord: () => post, + }; + + const dispatch = Object.assign( jest.fn(), { + receiveEntityRecords: jest.fn(), + } ); + // Provide entities + dispatch.mockReturnValueOnce( entities ); + + // Provide response + const updatedRecord = { ...post, id: 10 }; + apiFetch.mockImplementation( () => { + return updatedRecord; + } ); + + const result = await saveEntityRecord( + 'postType', + 'post', + post + )( { select, dispatch } ); + + expect( apiFetch ).toHaveBeenCalledTimes( 1 ); + expect( apiFetch ).toHaveBeenCalledWith( { + path: '/wp/v2/posts/10', + method: 'PUT', + data: post, + } ); + + expect( dispatch ).toHaveBeenCalledTimes( 5 ); + expect( dispatch ).toHaveBeenCalledWith( { + type: 'SAVE_ENTITY_RECORD_START', + kind: 'postType', + name: 'post', + recordId: 10, + isAutosave: false, + } ); + expect( dispatch ).toHaveBeenCalledWith( [ + { + type: 'MOCKED_ACQUIRE_LOCK', + }, + ] ); + expect( dispatch ).toHaveBeenCalledWith( { + type: 'SAVE_ENTITY_RECORD_FINISH', + kind: 'postType', + name: 'post', + recordId: 10, + error: undefined, + isAutosave: false, + } ); + expect( dispatch ).toHaveBeenCalledWith( [ + { + type: 'MOCKED_RELEASE_LOCK', + }, + ] ); + + expect( dispatch.receiveEntityRecords ).toHaveBeenCalledTimes( 1 ); + expect( dispatch.receiveEntityRecords ).toHaveBeenCalledWith( + 'postType', + 'post', + updatedRecord, + undefined, + true, + post + ); + + expect( result ).toBe( updatedRecord ); + } ); + + it( 'triggers a PUT request for an existing record with a custom key', async () => { + const postType = { slug: 'page', title: 'Pages' }; + const entities = [ + { + name: 'postType', + kind: 'root', + baseURL: '/wp/v2/types', + key: 'slug', + }, + ]; + const select = { + getRawEntityRecord: () => ( {} ), + }; + + const dispatch = Object.assign( jest.fn(), { + receiveEntityRecords: jest.fn(), + } ); + // Provide entities + dispatch.mockReturnValueOnce( entities ); + + // Provide response + apiFetch.mockImplementation( () => postType ); + + const result = await saveEntityRecord( + 'root', + 'postType', + postType + )( { select, dispatch } ); + + expect( apiFetch ).toHaveBeenCalledTimes( 1 ); + expect( apiFetch ).toHaveBeenCalledWith( { + path: '/wp/v2/types/page', + method: 'PUT', + data: postType, + } ); + + expect( dispatch ).toHaveBeenCalledTimes( 5 ); + expect( dispatch ).toHaveBeenCalledWith( { + type: 'SAVE_ENTITY_RECORD_START', + kind: 'root', + name: 'postType', + recordId: 'page', + isAutosave: false, + } ); + expect( dispatch ).toHaveBeenCalledWith( [ + { + type: 'MOCKED_ACQUIRE_LOCK', + }, + ] ); + expect( dispatch ).toHaveBeenCalledWith( { + type: 'SAVE_ENTITY_RECORD_FINISH', + kind: 'root', + name: 'postType', + recordId: 'page', + error: undefined, + isAutosave: false, + } ); + expect( dispatch ).toHaveBeenCalledWith( [ + { + type: 'MOCKED_RELEASE_LOCK', + }, + ] ); + + expect( dispatch.receiveEntityRecords ).toHaveBeenCalledTimes( 1 ); + expect( dispatch.receiveEntityRecords ).toHaveBeenCalledWith( + 'root', + 'postType', + postType, + undefined, + true, + { slug: 'page', title: 'Pages' } + ); + + expect( result ).toBe( postType ); + } ); +} ); describe( 'receiveUserPermission', () => { it( 'builds an action object', () => { From 389910fc6433e7cab87b03b5d72d3e2fe38df4ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Fri, 27 Aug 2021 12:52:15 +0200 Subject: [PATCH 08/14] Call dispatch.saveEntityRecord instead of dispatch( saveEntityRecord ) --- packages/core-data/src/actions.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index f292771f38aca0..bfa61e656137d3 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -695,9 +695,7 @@ export const __experimentalSaveSpecifiedEntityEdits = ( editsToSave[ edit ] = edits[ edit ]; } } - return await dispatch( - saveEntityRecord( kind, name, editsToSave, options ) - ); + return await dispatch.saveEntityRecord( kind, name, editsToSave, options ); }; /** From 467c67b9690e862b31adf95fff1660960652d136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Fri, 27 Aug 2021 12:54:08 +0200 Subject: [PATCH 09/14] Remove async/await from saveEditedEntityRecord and __experimentalSaveSpecifiedEntityEdits --- packages/core-data/src/actions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index bfa61e656137d3..4f27203b786057 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -662,7 +662,7 @@ export const saveEditedEntityRecord = ( recordId ); const record = { id: recordId, ...edits }; - return await dispatch( saveEntityRecord( kind, name, record, options ) ); + return await dispatch.saveEntityRecord( kind, name, record, options ); }; /** From 4852128966c86e21568343bc2d7c3633e091f1bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Fri, 27 Aug 2021 13:28:36 +0200 Subject: [PATCH 10/14] Make ifNotResolved return an enhanced resolver returning a promise and add a test case for that --- .../core-data/src/utils/if-not-resolved.js | 4 ++-- .../src/utils/test/if-not-resolved.js | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/core-data/src/utils/if-not-resolved.js b/packages/core-data/src/utils/if-not-resolved.js index 56b48d011157ca..653827cdfe6c02 100644 --- a/packages/core-data/src/utils/if-not-resolved.js +++ b/packages/core-data/src/utils/if-not-resolved.js @@ -10,12 +10,12 @@ * * @return {Function} Enhanced resolver. */ -const ifNotResolved = ( resolver, selectorName ) => ( ...args ) => ( { +const ifNotResolved = ( resolver, selectorName ) => ( ...args ) => async ( { select, dispatch, } ) => { if ( ! select.hasStartedResolution( selectorName, args ) ) { - dispatch( resolver( ...args ) ); + await dispatch( resolver( ...args ) ); } }; diff --git a/packages/core-data/src/utils/test/if-not-resolved.js b/packages/core-data/src/utils/test/if-not-resolved.js index eab3b04680065f..291e224b3833cd 100644 --- a/packages/core-data/src/utils/test/if-not-resolved.js +++ b/packages/core-data/src/utils/test/if-not-resolved.js @@ -54,4 +54,23 @@ describe( 'ifNotResolved', () => { expect( originalResolver ).toHaveBeenCalledTimes( 0 ); } ); + + it( 'returns a promise when the resolver was not already resolved', async () => { + const select = { hasStartedResolution: () => false }; + let thunkRetval; + const dispatch = jest.fn( ( thunk ) => { + thunkRetval = thunk(); + return thunkRetval; + } ); + + const originalResolver = jest.fn( () => () => + Promise.resolve( 'success!' ) + ); + + const resolver = ifNotResolved( originalResolver, 'originalResolver' ); + const result = resolver()( { select, dispatch } ); + + await expect( result ).resolves.toBe( undefined ); + await expect( thunkRetval ).resolves.toBe( 'success!' ); + } ); } ); From 6ea2d259d1830729a6a62c1a0e06550a43a5f93e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Fri, 27 Aug 2021 13:32:23 +0200 Subject: [PATCH 11/14] Quality-of-life refactor of __unstableFetch from if to a default argument --- docs/reference-guides/data/data-core.md | 2 +- packages/core-data/README.md | 2 +- packages/core-data/src/actions.js | 11 ++++------- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index 7ad08fa7f9ff22..9a05ac2983a7fb 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -702,7 +702,7 @@ _Parameters_ - _record_ `Object`: Record to be saved. - _options_ `Object`: Saving options. - _options.isAutosave_ `[boolean]`: Whether this is an autosave. -- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a control descriptor. +- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a control descriptor or a promise. ### undo diff --git a/packages/core-data/README.md b/packages/core-data/README.md index 96f6c1e300404e..8cff9b01e4270f 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -236,7 +236,7 @@ _Parameters_ - _record_ `Object`: Record to be saved. - _options_ `Object`: Saving options. - _options.isAutosave_ `[boolean]`: Whether this is an autosave. -- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a control descriptor. +- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a control descriptor or a promise. ### undo diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index 4f27203b786057..5382ceacfd8d9d 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -359,13 +359,13 @@ export function __unstableCreateUndoLevel() { * @param {Function} [options.__unstableFetch] Internal use only. Function to * call instead of `apiFetch()`. * Must return a control - * descriptor. + * descriptor or a promise. */ export const saveEntityRecord = ( kind, name, record, - { isAutosave = false, __unstableFetch = null } = {} + { isAutosave = false, __unstableFetch = triggerFetch } = {} ) => async ( { select, dispatch } ) => { const entities = await dispatch( getKindEntities( kind ) ); const entity = find( entities, { kind, name } ); @@ -461,11 +461,8 @@ export const saveEntityRecord = ( method: 'POST', data, }; - if ( __unstableFetch ) { - updatedRecord = await __unstableFetch( options ); - } else { - updatedRecord = await triggerFetch( options ); - } + updatedRecord = await __unstableFetch( options ); + // An autosave may be processed by the server as a regular save // when its update is requested by the author and the post had // draft or auto-draft status. From c214a26c964babbd74bb2eb6bd21e8fc0fc41dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Fri, 27 Aug 2021 13:35:32 +0200 Subject: [PATCH 12/14] Adjust the second instance of __unstableFetch --- packages/core-data/src/actions.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index 5382ceacfd8d9d..950b53705fd236 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -535,11 +535,7 @@ export const saveEntityRecord = ( method: recordId ? 'PUT' : 'POST', data: edits, }; - if ( __unstableFetch ) { - updatedRecord = await __unstableFetch( options ); - } else { - updatedRecord = await triggerFetch( options ); - } + updatedRecord = await __unstableFetch( options ); await dispatch.receiveEntityRecords( kind, name, From 9ac026a0aed132218bccc234b3a69f65e1bf4f1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Fri, 27 Aug 2021 14:17:49 +0200 Subject: [PATCH 13/14] Adjust the documentation of __unstableFetch to clarify it must be a promise, not a control descriptor --- docs/reference-guides/data/data-core.md | 2 +- packages/core-data/README.md | 2 +- packages/core-data/src/actions.js | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index 9a05ac2983a7fb..cfecc33470ab6c 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -702,7 +702,7 @@ _Parameters_ - _record_ `Object`: Record to be saved. - _options_ `Object`: Saving options. - _options.isAutosave_ `[boolean]`: Whether this is an autosave. -- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a control descriptor or a promise. +- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a promise. ### undo diff --git a/packages/core-data/README.md b/packages/core-data/README.md index 8cff9b01e4270f..4e906e79bb1be3 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -236,7 +236,7 @@ _Parameters_ - _record_ `Object`: Record to be saved. - _options_ `Object`: Saving options. - _options.isAutosave_ `[boolean]`: Whether this is an autosave. -- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a control descriptor or a promise. +- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a promise. ### undo diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index 950b53705fd236..fcc41bf5dd6cbf 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -358,8 +358,7 @@ export function __unstableCreateUndoLevel() { * @param {boolean} [options.isAutosave=false] Whether this is an autosave. * @param {Function} [options.__unstableFetch] Internal use only. Function to * call instead of `apiFetch()`. - * Must return a control - * descriptor or a promise. + * Must return a promise. */ export const saveEntityRecord = ( kind, From 09896256613ed1faf7f676680e0ec88fe5a49a1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Fri, 27 Aug 2021 16:50:02 +0200 Subject: [PATCH 14/14] Remove a commented line --- packages/core-data/src/test/actions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core-data/src/test/actions.js b/packages/core-data/src/test/actions.js index 11c5cb4f6d23f1..8ee805c489853c 100644 --- a/packages/core-data/src/test/actions.js +++ b/packages/core-data/src/test/actions.js @@ -13,7 +13,6 @@ import { editEntityRecord, saveEntityRecord, deleteEntityRecord, - // receiveEntityRecords, receiveUserPermission, receiveAutosaves, receiveCurrentUser,