@wordpress/api-fetch
Version:
Utility to make WordPress REST API requests.
343 lines (291 loc) • 8.44 kB
JavaScript
/**
* Internal dependencies
*/
import createPreloadingMiddleware from '../preloading';
describe( 'Preloading Middleware', () => {
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();
preloadingMiddleware( requestOptions, nextSpy );
expect( nextSpy ).not.toHaveBeenCalled();
preloadingMiddleware( requestOptions, nextSpy );
expect( nextSpy ).toHaveBeenCalled();
} );
} );
describe( 'and the OPTIONS request has a parse flag', () => {
it( 'should return the full response if parse: false', () => {
const noResponseMock =
'undefined' === typeof window.Response;
if ( noResponseMock ) {
window.Response = class {
constructor( body, options ) {
this.body = JSON.parse( body );
this.headers = options.headers;
}
};
}
const data = {
body: {
status: 'this is the preloaded response',
},
headers: {
Allow: 'GET, POST',
},
};
const preloadedData = {
OPTIONS: {
'wp/v2/posts': data,
},
};
const preloadingMiddleware =
createPreloadingMiddleware( preloadedData );
const requestOptions = {
method: 'OPTIONS',
path: 'wp/v2/posts',
parse: false,
};
const response = preloadingMiddleware( requestOptions );
if ( noResponseMock ) {
delete window.Response;
}
return response.then( ( value ) => {
expect( value ).toEqual( data );
} );
} );
it( 'should return only the response body if parse: true', () => {
const body = {
status: 'this is the preloaded response',
};
const preloadedData = {
OPTIONS: {
'wp/v2/posts': {
body,
headers: {
Allow: 'GET, POST',
},
},
},
};
const preloadingMiddleware =
createPreloadingMiddleware( preloadedData );
const requestOptions = {
method: 'OPTIONS',
path: 'wp/v2/posts',
parse: true,
};
const response = preloadingMiddleware( requestOptions );
return response.then( ( value ) => {
expect( value ).toEqual( body );
} );
} );
} );
} );
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();
} );
} );
} );
it( 'should normalize on stable path', async () => {
const body = { content: 'example' };
const preloadedData = {
'wp/v2/demo-reverse-alphabetical?foo=bar&baz=quux': { body },
'wp/v2/demo-alphabetical?baz=quux&foo=bar': { body },
};
const preloadingMiddleware =
createPreloadingMiddleware( preloadedData );
let requestOptions = {
method: 'GET',
path: 'wp/v2/demo-reverse-alphabetical?baz=quux&foo=bar',
};
let value = await preloadingMiddleware( requestOptions, () => {} );
expect( value ).toEqual( body );
requestOptions = {
method: 'GET',
path: 'wp/v2/demo-alphabetical?foo=bar&baz=quux',
};
value = await preloadingMiddleware( requestOptions, () => {} );
expect( value ).toEqual( body );
} );
it( 'should recognize an urlencoded query param', async () => {
const body = { foo: 'foo', bar: 'bar' };
const preloadingMiddleware = createPreloadingMiddleware( {
'/?_fields=foo,bar': { body },
} );
const response = await preloadingMiddleware(
{
method: 'GET',
path: '/?_fields=foo%2Cbar',
},
() => {}
);
expect( response ).toEqual( body );
} );
it( 'should recognize rest_route query param as path', async () => {
const body = { foo: 'foo' };
const preloadingMiddleware = createPreloadingMiddleware( {
'/': { body },
} );
const response = await preloadingMiddleware(
{
method: 'GET',
url: '/index.php?rest_route=%2F',
},
() => {}
);
expect( response ).toEqual( body );
} );
it( 'should recognize additional query params after rest_route', async () => {
const body = { foo: 'foo', bar: 'bar' };
const preloadingMiddleware = createPreloadingMiddleware( {
'/?_fields=foo,bar': { body },
} );
const response = await preloadingMiddleware(
{
method: 'GET',
url: '/index.php?rest_route=%2F&_fields=foo%2Cbar',
},
() => {}
);
expect( response ).toEqual( body );
} );
it( 'should remove OPTIONS type requests from the cache after the first hit', async () => {
const body = { content: 'example' };
const preloadedData = {
OPTIONS: {
'wp/v2/demo': { body },
},
};
const preloadingMiddleware =
createPreloadingMiddleware( preloadedData );
const requestOptions = {
method: 'OPTIONS',
path: 'wp/v2/demo',
};
const firstMiddleware = jest.fn();
preloadingMiddleware( requestOptions, firstMiddleware );
expect( firstMiddleware ).not.toHaveBeenCalled();
await preloadingMiddleware( requestOptions, firstMiddleware );
const secondMiddleware = jest.fn();
await preloadingMiddleware( requestOptions, secondMiddleware );
expect( secondMiddleware ).toHaveBeenCalledTimes( 1 );
} );
it( 'should not throw an error when non-ASCII headers are present', async () => {
const noResponseMock = 'undefined' === typeof window.Response;
if ( noResponseMock ) {
window.Response = class {
constructor( body, options ) {
this.body = JSON.parse( body );
this.headers = options.headers;
// Check for non-ASCII characters in headers
for ( const [ key, value ] of Object.entries(
this.headers || {}
) ) {
if ( /[^\x00-\x7F]/.test( value ) ) {
throw new Error(
`Invalid non-ASCII character found in header: ${ key }`
);
}
}
}
};
}
const data = {
body: 'Hello',
headers: {
Link: '<http://example.com/ویدیو/example>; rel="alternate"; type=text/html',
},
};
const preloadedData = {
'wp/v2/example': data,
};
const preloadingMiddleware =
createPreloadingMiddleware( preloadedData );
const requestOptions = {
method: 'GET',
path: 'wp/v2/example',
parse: false,
};
await expect(
preloadingMiddleware( requestOptions, () => {} )
).resolves.not.toThrow();
if ( noResponseMock ) {
delete window.Response;
}
} );
describe.each( [ [ 'GET' ], [ 'OPTIONS' ] ] )( '%s', ( method ) => {
describe.each( [
[ 'all empty', {} ],
[ 'method empty', { [ method ]: {} } ],
] )( '%s', ( label, preloadedData ) => {
it( 'should move to the next middleware if no preloaded data', () => {
const preloadingMiddleware =
createPreloadingMiddleware( preloadedData );
const requestOptions = {
method,
path: 'wp/v2/posts',
};
const callback = ( options ) => {
expect( options ).toBe( requestOptions );
return true;
};
const ret = preloadingMiddleware( requestOptions, callback );
expect( ret ).toBe( true );
} );
} );
} );
} );