Skip to content

Commit

Permalink
[apiFetch] Fix preloading middleware referencing stale data (#25550)
Browse files Browse the repository at this point in the history
The logic for preloading middleware in the apiFetch library caches preloaded data. As it stands today, all requests to the preloaded endpoint will reference the cache.

The problem is that the cache is never invalidated during a session. When updates are persisted to the WordPress database, the cache doesn't change, and it will continue to reference the stale, preloaded data.

This fix only allows references to cached data for each preloaded endpoint a single time, after which all subsequent requests to preloaded endpoints will skip preloading middleware.
  • Loading branch information
jeyip authored Sep 24, 2020
1 parent 093bdf0 commit 57e2151
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 22 deletions.
11 changes: 8 additions & 3 deletions packages/api-fetch/src/middlewares/preloading.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,20 @@ function createPreloadingMiddleware( preloadedData ) {
const path = getStablePath( options.path );

if ( 'GET' === method && cache[ path ] ) {
const cacheData = cache[ path ];

// Unsetting the cache key ensures that the data is only preloaded a single time
delete cache[ path ];

return Promise.resolve(
parse
? cache[ path ].body
? cacheData.body
: new window.Response(
JSON.stringify( cache[ path ].body ),
JSON.stringify( cacheData.body ),
{
status: 200,
statusText: 'OK',
headers: cache[ path ].headers,
headers: cacheData.headers,
}
)
);
Expand Down
94 changes: 75 additions & 19 deletions packages/api-fetch/src/middlewares/test/preloading.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,82 @@ describe( 'Preloading Middleware', () => {
} );
} );

it( 'should return the preloaded data if provided', () => {
const body = {
status: 'this is the preloaded response',
};
const preloadedData = {
'wp/v2/posts': {
body,
},
};
const preloadingMiddleware = createPreloadingMiddleware(
preloadedData
);
const requestOptions = {
method: 'GET',
path: 'wp/v2/posts',
};
describe( 'given preloaded data', () => {
describe( 'when data is requested from a preloaded endpoint', () => {
describe( 'and it is requested for the first time', () => {
it( 'should return the preloaded data', () => {
const body = {
status: 'this is the preloaded response',
};
const preloadedData = {
'wp/v2/posts': {
body,
},
};
const preloadingMiddleware = createPreloadingMiddleware(
preloadedData
);
const requestOptions = {
method: 'GET',
path: 'wp/v2/posts',
};

const response = preloadingMiddleware( requestOptions );
return response.then( ( value ) => {
expect( value ).toEqual( body );
} );
} );
} );

describe( 'and it has already been requested', () => {
it( 'should not return the preloaded data', () => {
const body = {
status: 'this is the preloaded response',
};
const preloadedData = {
'wp/v2/posts': {
body,
},
};
const preloadingMiddleware = createPreloadingMiddleware(
preloadedData
);
const requestOptions = {
method: 'GET',
path: 'wp/v2/posts',
};
const nextSpy = jest.fn();

const response = preloadingMiddleware( requestOptions );
return response.then( ( value ) => {
expect( value ).toEqual( body );
preloadingMiddleware( requestOptions, nextSpy );
expect( nextSpy ).not.toHaveBeenCalled();
preloadingMiddleware( requestOptions, nextSpy );
expect( nextSpy ).toHaveBeenCalled();
} );
} );
} );

describe( 'when the requested data is not from a preloaded endpoint', () => {
it( 'should not return preloaded data', () => {
const body = {
status: 'this is the preloaded response',
};
const preloadedData = {
'wp/v2/posts': {
body,
},
};
const preloadingMiddleware = createPreloadingMiddleware(
preloadedData
);
const requestOptions = {
method: 'GET',
path: 'wp/v2/fake_resource',
};
const nextSpy = jest.fn();

preloadingMiddleware( requestOptions, nextSpy );
expect( nextSpy ).toHaveBeenCalled();
} );
} );
} );

Expand Down

0 comments on commit 57e2151

Please sign in to comment.