Add fetch tests from WVUI

Bug: T288686
Change-Id: Ifeb2e355482d3d5920c2535c89193cc4f36a13c9
This commit is contained in:
bwang 2022-02-14 14:12:03 -06:00
parent 2a83dad477
commit a560fb814a
5 changed files with 158 additions and 55 deletions

View File

@ -28,10 +28,10 @@ module.exports = {
// An object that configures minimum threshold enforcement for coverage results
coverageThreshold: {
global: {
branches: 0,
functions: 0,
lines: 0,
statements: 0
branches: 6,
functions: 12,
lines: 8,
statements: 8
}
},

View File

@ -0,0 +1,53 @@
/**
* @typedef {Object} AbortableFetch
* @property {Promise<any>} fetch
* @property {Function} abort
*/
/**
* @typedef {Object} NullableAbortController
* @property {AbortSignal | undefined} signal
* @property {Function} abort
*/
const nullAbortController = {
signal: undefined,
abort: () => {} // Do nothing (no-op)
};
/**
* A wrapper which combines native fetch() in browsers and the following json() call.
*
* @param {string} resource
* @param {RequestInit} [init]
* @return {AbortableFetch}
*/
function fetchJson( resource, init ) {
// As of 2020, browser support for AbortController is limited:
// https://caniuse.com/abortcontroller
// so replacing it with no-op if it doesn't exist.
/* eslint-disable compat/compat */
const controller = window.AbortController ?
new AbortController() :
nullAbortController;
/* eslint-enable compat/compat */
const getJson = fetch( resource, $.extend( init, {
signal: controller.signal
} ) ).then( ( response ) => {
if ( !response.ok ) {
return Promise.reject(
'Network request failed with HTTP code ' + response.status
);
}
return response.json();
} );
return {
fetch: getJson,
abort: () => {
controller.abort();
}
};
}
module.exports = fetchJson;

View File

@ -1,56 +1,6 @@
/** @module restSearchClient */
/**
* @typedef {Object} AbortableFetch
* @property {Promise<any>} fetch
* @property {Function} abort
*/
/**
* @typedef {Object} NullableAbortController
* @property {AbortSignal | undefined} signal
* @property {Function} abort
*/
const nullAbortController = {
signal: undefined,
abort: () => {} // Do nothing (no-op)
};
/**
* A wrapper which combines native fetch() in browsers and the following json() call.
*
* @param {string} resource
* @param {RequestInit} [init]
* @return {AbortableFetch}
*/
function fetchJson( resource, init ) {
// As of 2020, browser support for AbortController is limited:
// https://caniuse.com/abortcontroller
// so replacing it with no-op if it doesn't exist.
/* eslint-disable compat/compat */
const controller = window.AbortController ?
new AbortController() :
nullAbortController;
/* eslint-enable compat/compat */
const getJson = fetch( resource, $.extend( init, {
signal: controller.signal
} ) ).then( ( response ) => {
if ( !response.ok ) {
return Promise.reject(
'Network request failed with HTTP code ' + response.status
);
}
return response.json();
} );
return {
fetch: getJson,
abort: () => {
controller.abort();
}
};
}
const fetchJson = require( './fetch.js' );
/**
* @typedef {Object} RestResponse

View File

@ -145,6 +145,7 @@
"packageFiles": [
"resources/skins.vector.search/skins.vector.search.js",
"resources/skins.vector.search/instrumentation.js",
"resources/skins.vector.search/fetch.js",
"resources/skins.vector.search/restSearchClient.js",
"resources/skins.vector.search/App.vue",
{

99
tests/jest/fetch.test.js Normal file
View File

@ -0,0 +1,99 @@
/* global fetchMock */
const fetchJson = require( '../../resources/skins.vector.search/fetch.js' );
const jestFetchMock = require( 'jest-fetch-mock' );
const mockedRequests = !process.env.TEST_LIVE_REQUESTS;
const url = '//en.wikipedia.org/w/rest.php/v1/search/title?q=jfgkdajgioj&limit=10';
describe( 'abort() using AbortController', () => {
test( 'Aborting an unfinished request throws an AbortError', async () => {
expect.assertions( 1 );
const { abort, fetch } = fetchJson( url );
abort();
return fetch.catch( ( e ) => {
expect( e.name ).toStrictEqual( 'AbortError' );
} );
} );
} );
describe( 'fetch() using window.fetch', () => {
beforeAll( () => {
jestFetchMock.enableFetchMocks();
} );
afterAll( () => {
jestFetchMock.disableFetchMocks();
} );
beforeEach( () => {
fetchMock.resetMocks();
if ( !mockedRequests ) {
fetchMock.disableMocks();
}
fetchMock.mockIf( /^\/\/en.wikipedia.org\//, async ( req ) => {
if ( req.url === url ) {
return {
body: JSON.stringify( { pages: [] } ),
headers: {
'Content-Type': 'application/json'
}
};
} else {
return {
status: 404,
body: 'Page not found'
};
}
} );
} );
test( '200 without init param passed', async () => {
const { fetch } = fetchJson( url );
const json = await fetch;
// eslint-disable-next-line compat/compat
const controller = new AbortController();
expect( json ).toStrictEqual( { pages: [] } );
if ( mockedRequests ) {
expect( fetchMock ).toHaveBeenCalledTimes( 1 );
expect( fetchMock ).toHaveBeenCalledWith( url, { signal: controller.signal } );
}
} );
test( '200 with init param passed', async () => {
const { fetch } = fetchJson( url, { mode: 'cors' } );
const json = await fetch;
expect( json ).toStrictEqual( { pages: [] } );
if ( mockedRequests ) {
expect( fetchMock ).toHaveBeenCalledTimes( 1 );
expect( fetchMock ).toHaveBeenCalledWith(
url,
expect.objectContaining( { mode: 'cors' } )
);
}
} );
test( '404 response', async () => {
expect.assertions( 1 );
const { fetch } = fetchJson( '//en.wikipedia.org/doesNotExist' );
await expect( fetch )
.rejects.toStrictEqual( 'Network request failed with HTTP code 404' );
if ( mockedRequests ) {
const controller = new AbortController();
expect.assertions( 3 );
expect( fetchMock ).toHaveBeenCalledTimes( 1 );
expect( fetchMock ).toHaveBeenCalledWith(
'//en.wikipedia.org/doesNotExist', { signal: controller.signal }
);
}
} );
} );