144 lines
5.2 KiB
JavaScript
144 lines
5.2 KiB
JavaScript
import { expect } from '@open-wc/testing';
|
|
import sinon from 'sinon';
|
|
|
|
import { AjaxClass } from '../src/AjaxClass.js';
|
|
|
|
describe('AjaxClass interceptors', () => {
|
|
/** @type {import('sinon').SinonFakeServer} */
|
|
let server;
|
|
|
|
/**
|
|
* @param {Object} [cfg] configuration for the AjaxClass instance
|
|
* @param {string} cfg.jsonPrefix prefixing the JSON string in this manner is used to help
|
|
* prevent JSON Hijacking. The prefix renders the string syntactically invalid as a script so
|
|
* that it cannot be hijacked. This prefix should be stripped before parsing the string as JSON.
|
|
* @param {string} cfg.lang language
|
|
* @param {boolean} cfg.languageHeader the Accept-Language request HTTP header advertises
|
|
* which languages the client is able to understand, and which locale variant is preferred.
|
|
* @param {boolean} cfg.cancelable if request can be canceled
|
|
* @param {boolean} cfg.cancelPreviousOnNewRequest prevents concurrent requests
|
|
*/
|
|
function getInstance(cfg) {
|
|
return new AjaxClass(cfg);
|
|
}
|
|
|
|
beforeEach(() => {
|
|
server = sinon.fakeServer.create({ autoRespond: true });
|
|
});
|
|
|
|
afterEach(() => {
|
|
server.restore();
|
|
});
|
|
|
|
describe('use cases', () => {
|
|
it('can be added on a class for all instances', () => {
|
|
['requestInterceptors', 'responseInterceptors'].forEach(type => {
|
|
const myInterceptor = () => {};
|
|
class MyApi extends AjaxClass {
|
|
constructor() {
|
|
super();
|
|
this[type] = [...this[type], myInterceptor];
|
|
}
|
|
}
|
|
const ajaxWithout = getInstance();
|
|
const ajaxWith = new MyApi();
|
|
expect(ajaxWithout[type]).to.not.include(myInterceptor);
|
|
expect(ajaxWith[type]).to.include(myInterceptor);
|
|
});
|
|
});
|
|
|
|
it('can be added per instance without changing the class', () => {
|
|
['requestInterceptors', 'responseInterceptors'].forEach(type => {
|
|
const myInterceptor = () => {};
|
|
const ajaxWithout = getInstance();
|
|
const ajaxWith = getInstance();
|
|
ajaxWith[type].push(myInterceptor);
|
|
expect(ajaxWithout[type]).to.not.include(myInterceptor);
|
|
expect(ajaxWith[type]).to.include(myInterceptor);
|
|
});
|
|
});
|
|
|
|
it('can be removed after request', async () => {
|
|
await Promise.all(
|
|
['requestInterceptors', 'responseInterceptors'].map(async type => {
|
|
server.respondWith('GET', 'data.json', [
|
|
200,
|
|
{ 'Content-Type': 'application/json' },
|
|
'{}',
|
|
]);
|
|
|
|
const myInterceptor = sinon.spy(foo => foo);
|
|
|
|
const ajax = getInstance();
|
|
|
|
ajax[type].push(myInterceptor);
|
|
await ajax.get('data.json');
|
|
|
|
ajax[type] = ajax[type].filter(/** @param {?} item */ item => item !== myInterceptor);
|
|
await ajax.get('data.json');
|
|
|
|
expect(myInterceptor.callCount).to.eql(1);
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('has access to provided instance config(options) on requestInterceptors', async () => {
|
|
server.respondWith('GET', 'data.json', [200, { 'Content-Type': 'application/json' }, '{}']);
|
|
const ajax = getInstance();
|
|
// @ts-ignore setting a prop that isn't existing on options
|
|
ajax.options.myCustomValue = 'foo';
|
|
let customValueAccess = false;
|
|
const myInterceptor = /** @param {{[key: string]: ?}} config */ config => {
|
|
customValueAccess = config.myCustomValue === 'foo';
|
|
return config;
|
|
};
|
|
// @ts-ignore butchered something here..
|
|
ajax.requestInterceptors.push(myInterceptor);
|
|
await ajax.get('data.json');
|
|
expect(customValueAccess).to.eql(true);
|
|
});
|
|
});
|
|
|
|
describe('requestInterceptors', () => {
|
|
it('allow to intercept request to change config', async () => {
|
|
server.respondWith('POST', 'data.json', [
|
|
200,
|
|
{ 'Content-Type': 'application/json' },
|
|
'{ "method": "post" }',
|
|
]);
|
|
server.respondWith('PUT', 'data.json', [
|
|
200,
|
|
{ 'Content-Type': 'application/json' },
|
|
'{ "method": "put" }',
|
|
]);
|
|
const enforcePutInterceptor = /** @param {{[key: string]: ?}} config */ config => ({
|
|
...config,
|
|
method: 'PUT',
|
|
});
|
|
const myAjax = getInstance();
|
|
// @ts-ignore butchered something here..
|
|
myAjax.requestInterceptors.push(enforcePutInterceptor);
|
|
const response = await myAjax.post('data.json');
|
|
expect(response.data).to.deep.equal({ method: 'put' });
|
|
});
|
|
});
|
|
|
|
describe('responseInterceptors', () => {
|
|
it('allow to intercept response to change data', async () => {
|
|
server.respondWith('GET', 'data.json', [
|
|
200,
|
|
{ 'Content-Type': 'application/json' },
|
|
'{ "method": "get" }',
|
|
]);
|
|
const addDataInterceptor = /** @param {{[key: string]: ?}} config */ config => ({
|
|
...config,
|
|
data: { ...config.data, foo: 'bar' },
|
|
});
|
|
const myAjax = getInstance();
|
|
// @ts-ignore I probably butchered the types here or adding data like above is simply not allowed in Response objects
|
|
myAjax.responseInterceptors.push(addDataInterceptor);
|
|
const response = await myAjax.get('data.json');
|
|
expect(response.data).to.deep.equal({ method: 'get', foo: 'bar' });
|
|
});
|
|
});
|
|
});
|